From c14d0f6982c620f1732d3e06822e51486801e960 Mon Sep 17 00:00:00 2001 From: Mike Simkins Date: Wed, 1 Sep 2010 14:56:52 +0100 Subject: [PATCH] Initial Commit from Base app --- .gitignore | 4 + .rspec | 1 + Gemfile | 46 ++++ Gemfile.lock | 201 +++++++++++++++ README | 256 +++++++++++++++++++ Rakefile | 7 + app/controllers/application_controller.rb | 10 + app/controllers/portal_controller.rb | 8 + app/helpers/application_helper.rb | 2 + app/helpers/portal_helper.rb | 2 + app/models/ability.rb | 14 ++ app/models/role.rb | 4 + app/models/user.rb | 16 ++ app/views/devise/confirmations/new.html.erb | 12 + .../mailer/confirmation_instructions.html.erb | 5 + .../mailer/reset_password_instructions.html.erb | 8 + .../devise/mailer/unlock_instructions.html.erb | 7 + app/views/devise/passwords/edit.html.erb | 16 ++ app/views/devise/passwords/new.html.erb | 12 + app/views/devise/registrations/edit.html.erb | 25 ++ app/views/devise/registrations/new.html.erb | 18 ++ app/views/devise/sessions/new.html.erb | 17 ++ app/views/devise/shared/_links.erb | 19 ++ app/views/devise/unlocks/new.html.erb | 12 + app/views/layouts/application.html.erb | 21 ++ app/views/portal/index.html.erb | 2 + autotest/discover.rb | 2 + config.ru | 4 + config/application.rb | 47 ++++ config/boot.rb | 13 + config/cucumber.yml | 8 + config/database.yml | 42 ++++ config/environment.rb | 5 + config/environments/development.rb | 26 ++ config/environments/production.rb | 49 ++++ config/environments/test.rb | 35 +++ config/initializers/backtrace_silencers.rb | 7 + config/initializers/devise.rb | 146 +++++++++++ config/initializers/inflections.rb | 10 + config/initializers/jquery.rb | 12 + config/initializers/mime_types.rb | 5 + config/initializers/secret_token.rb | 7 + config/initializers/session_store.rb | 8 + config/locales/devise.en.yml | 39 +++ config/locales/en.yml | 5 + config/routes.rb | 60 +++++ db/migrate/20100901113751_devise_create_users.rb | 26 ++ .../20100901125355_create_cancan_role_migration.rb | 12 + ...01125550_users_have_and_belong_to_many_roles.rb | 11 + ...100901130613_add_invitable_options_to_devise.rb | 14 ++ db/schema.rb | 53 ++++ db/seeds.rb | 7 + doc/README_FOR_APP | 2 + features/devise.feature | 18 ++ features/step_definitions/devise.rb | 22 ++ features/step_definitions/web_steps.rb | 219 ++++++++++++++++ features/support/env.rb | 57 +++++ features/support/paths.rb | 35 +++ lib/tasks/.gitkeep | 0 lib/tasks/cucumber.rake | 53 ++++ public/404.html | 26 ++ public/422.html | 26 ++ public/500.html | 26 ++ public/favicon.ico | 0 public/images/rails.png | Bin 0 -> 6646 bytes public/javascripts/application.js | 2 + public/javascripts/jquery.js | 154 ++++++++++++ public/javascripts/rails.js | 132 ++++++++++ public/robots.txt | 5 + public/stylesheets/.gitkeep | 0 public/stylesheets/blueprint/ie.css | 35 +++ .../blueprint/plugins/buttons/icons/cross.png | Bin 0 -> 655 bytes .../blueprint/plugins/buttons/icons/key.png | Bin 0 -> 455 bytes .../blueprint/plugins/buttons/icons/tick.png | Bin 0 -> 537 bytes .../blueprint/plugins/buttons/readme.txt | 32 +++ .../blueprint/plugins/buttons/screen.css | 97 +++++++ .../blueprint/plugins/fancy-type/readme.txt | 14 ++ .../blueprint/plugins/fancy-type/screen.css | 71 ++++++ .../blueprint/plugins/link-icons/icons/doc.png | Bin 0 -> 777 bytes .../blueprint/plugins/link-icons/icons/email.png | Bin 0 -> 641 bytes .../plugins/link-icons/icons/external.png | Bin 0 -> 46848 bytes .../blueprint/plugins/link-icons/icons/feed.png | Bin 0 -> 691 bytes .../blueprint/plugins/link-icons/icons/im.png | Bin 0 -> 741 bytes .../blueprint/plugins/link-icons/icons/pdf.png | Bin 0 -> 591 bytes .../blueprint/plugins/link-icons/icons/visited.png | Bin 0 -> 46990 bytes .../blueprint/plugins/link-icons/icons/xls.png | Bin 0 -> 663 bytes .../blueprint/plugins/link-icons/readme.txt | 18 ++ .../blueprint/plugins/link-icons/screen.css | 40 +++ .../stylesheets/blueprint/plugins/rtl/readme.txt | 10 + .../stylesheets/blueprint/plugins/rtl/screen.css | 110 ++++++++ public/stylesheets/blueprint/print.css | 29 +++ public/stylesheets/blueprint/screen.css | 258 +++++++++++++++++++ public/stylesheets/blueprint/src/forms.css | 65 +++++ public/stylesheets/blueprint/src/grid.css | 280 +++++++++++++++++++++ public/stylesheets/blueprint/src/grid.png | Bin 0 -> 195 bytes public/stylesheets/blueprint/src/ie.css | 76 ++++++ public/stylesheets/blueprint/src/print.css | 85 +++++++ public/stylesheets/blueprint/src/reset.css | 45 ++++ public/stylesheets/blueprint/src/typography.css | 106 ++++++++ script/cucumber | 10 + script/rails | 6 + spec/controllers/portal_controller_spec.rb | 12 + spec/helpers/portal_helper_spec.rb | 15 ++ spec/models/user_spec.rb | 5 + spec/spec_helper.rb | 26 ++ spec/views/portal/index.html.erb_spec.rb | 2 + vendor/plugins/.gitkeep | 0 vendor/plugins/ssl_requirement/README | 43 ++++ .../plugins/ssl_requirement/lib/ssl_requirement.rb | 62 +++++ .../ssl_requirement/test/ssl_requirement_test.rb | 132 ++++++++++ 110 files changed, 3859 insertions(+) create mode 100644 .gitignore create mode 100644 .rspec create mode 100644 Gemfile create mode 100644 Gemfile.lock create mode 100644 README create mode 100644 Rakefile create mode 100644 app/controllers/application_controller.rb create mode 100644 app/controllers/portal_controller.rb create mode 100644 app/helpers/application_helper.rb create mode 100644 app/helpers/portal_helper.rb create mode 100644 app/models/ability.rb create mode 100644 app/models/role.rb create mode 100644 app/models/user.rb create mode 100644 app/views/devise/confirmations/new.html.erb create mode 100644 app/views/devise/mailer/confirmation_instructions.html.erb create mode 100644 app/views/devise/mailer/reset_password_instructions.html.erb create mode 100644 app/views/devise/mailer/unlock_instructions.html.erb create mode 100644 app/views/devise/passwords/edit.html.erb create mode 100644 app/views/devise/passwords/new.html.erb create mode 100644 app/views/devise/registrations/edit.html.erb create mode 100644 app/views/devise/registrations/new.html.erb create mode 100644 app/views/devise/sessions/new.html.erb create mode 100644 app/views/devise/shared/_links.erb create mode 100644 app/views/devise/unlocks/new.html.erb create mode 100644 app/views/layouts/application.html.erb create mode 100644 app/views/portal/index.html.erb create mode 100644 autotest/discover.rb create mode 100644 config.ru create mode 100644 config/application.rb create mode 100644 config/boot.rb create mode 100644 config/cucumber.yml create mode 100644 config/database.yml create mode 100644 config/environment.rb create mode 100644 config/environments/development.rb create mode 100644 config/environments/production.rb create mode 100644 config/environments/test.rb create mode 100644 config/initializers/backtrace_silencers.rb create mode 100644 config/initializers/devise.rb create mode 100644 config/initializers/inflections.rb create mode 100644 config/initializers/jquery.rb create mode 100644 config/initializers/mime_types.rb create mode 100644 config/initializers/secret_token.rb create mode 100644 config/initializers/session_store.rb create mode 100644 config/locales/devise.en.yml create mode 100644 config/locales/en.yml create mode 100644 config/routes.rb create mode 100644 db/migrate/20100901113751_devise_create_users.rb create mode 100644 db/migrate/20100901125355_create_cancan_role_migration.rb create mode 100644 db/migrate/20100901125550_users_have_and_belong_to_many_roles.rb create mode 100644 db/migrate/20100901130613_add_invitable_options_to_devise.rb create mode 100644 db/schema.rb create mode 100644 db/seeds.rb create mode 100644 doc/README_FOR_APP create mode 100644 features/devise.feature create mode 100644 features/step_definitions/devise.rb create mode 100644 features/step_definitions/web_steps.rb create mode 100644 features/support/env.rb create mode 100644 features/support/paths.rb create mode 100644 lib/tasks/.gitkeep create mode 100644 lib/tasks/cucumber.rake create mode 100644 public/404.html create mode 100644 public/422.html create mode 100644 public/500.html create mode 100644 public/favicon.ico create mode 100644 public/images/rails.png create mode 100644 public/javascripts/application.js create mode 100644 public/javascripts/jquery.js create mode 100644 public/javascripts/rails.js create mode 100644 public/robots.txt create mode 100644 public/stylesheets/.gitkeep create mode 100644 public/stylesheets/blueprint/ie.css create mode 100755 public/stylesheets/blueprint/plugins/buttons/icons/cross.png create mode 100755 public/stylesheets/blueprint/plugins/buttons/icons/key.png create mode 100755 public/stylesheets/blueprint/plugins/buttons/icons/tick.png create mode 100644 public/stylesheets/blueprint/plugins/buttons/readme.txt create mode 100644 public/stylesheets/blueprint/plugins/buttons/screen.css create mode 100644 public/stylesheets/blueprint/plugins/fancy-type/readme.txt create mode 100644 public/stylesheets/blueprint/plugins/fancy-type/screen.css create mode 100644 public/stylesheets/blueprint/plugins/link-icons/icons/doc.png create mode 100644 public/stylesheets/blueprint/plugins/link-icons/icons/email.png create mode 100644 public/stylesheets/blueprint/plugins/link-icons/icons/external.png create mode 100644 public/stylesheets/blueprint/plugins/link-icons/icons/feed.png create mode 100644 public/stylesheets/blueprint/plugins/link-icons/icons/im.png create mode 100644 public/stylesheets/blueprint/plugins/link-icons/icons/pdf.png create mode 100644 public/stylesheets/blueprint/plugins/link-icons/icons/visited.png create mode 100644 public/stylesheets/blueprint/plugins/link-icons/icons/xls.png create mode 100644 public/stylesheets/blueprint/plugins/link-icons/readme.txt create mode 100644 public/stylesheets/blueprint/plugins/link-icons/screen.css create mode 100644 public/stylesheets/blueprint/plugins/rtl/readme.txt create mode 100644 public/stylesheets/blueprint/plugins/rtl/screen.css create mode 100644 public/stylesheets/blueprint/print.css create mode 100644 public/stylesheets/blueprint/screen.css create mode 100644 public/stylesheets/blueprint/src/forms.css create mode 100755 public/stylesheets/blueprint/src/grid.css create mode 100644 public/stylesheets/blueprint/src/grid.png create mode 100644 public/stylesheets/blueprint/src/ie.css create mode 100755 public/stylesheets/blueprint/src/print.css create mode 100755 public/stylesheets/blueprint/src/reset.css create mode 100644 public/stylesheets/blueprint/src/typography.css create mode 100755 script/cucumber create mode 100755 script/rails create mode 100644 spec/controllers/portal_controller_spec.rb create mode 100644 spec/helpers/portal_helper_spec.rb create mode 100644 spec/models/user_spec.rb create mode 100644 spec/spec_helper.rb create mode 100644 spec/views/portal/index.html.erb_spec.rb create mode 100644 vendor/plugins/.gitkeep create mode 100644 vendor/plugins/ssl_requirement/README create mode 100644 vendor/plugins/ssl_requirement/lib/ssl_requirement.rb create mode 100644 vendor/plugins/ssl_requirement/test/ssl_requirement_test.rb diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..af64fae --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.bundle +db/*.sqlite3 +log/*.log +tmp/**/* diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..53607ea --- /dev/null +++ b/.rspec @@ -0,0 +1 @@ +--colour diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..38b366c --- /dev/null +++ b/Gemfile @@ -0,0 +1,46 @@ +source 'http://rubygems.org' + +gem 'rails', '3.0.0' + +# Bundle edge Rails instead: +# gem 'rails', :git => 'git://github.com/rails/rails.git' + +gem 'mysql2' +gem "devise", "~> 1.1.2" +gem "devise_invitable", :git => "git://github.com/rymai/devise_invitable.git" +gem 'capistrano' +gem 'cancan' +gem 'formtastic', :git => "http://github.com/justinfrench/formtastic.git", :branch => "rails3" + +# Use unicorn as the web server +# gem 'unicorn' + +# Deploy with Capistrano +# gem 'capistrano' + +# To use debugger +# gem 'ruby-debug' + +# Bundle the extra gems: +# gem 'bj' +# gem 'nokogiri' +# gem 'sqlite3-ruby', :require => 'sqlite3' +# gem 'aws-s3', :require => 'aws/s3' + +# Bundle gems for the local environment. Make sure to +# put test-only gems in this group so their generators +# and rake tasks are available in development mode: +group :development, :test do + gem 'capybara' + gem 'cucumber' + gem 'cucumber-rails' + gem "rspec-rails", ">= 2.0.0.beta.20", :git => "git://github.com/rspec/rspec-rails.git" + gem "rspec", ">= 2.0.0.beta.20", :git => "git://github.com/rspec/rspec.git" + gem "rspec-core", ">= 2.0.0.beta.20", :git => "git://github.com/rspec/rspec-core.git" + gem "rspec-expectations", ">= 2.0.0.beta.20", :git => "git://github.com/rspec/rspec-expectations.git" + gem "rspec-mocks", ">= 2.0.0.beta.20", :git => "git://github.com/rspec/rspec-mocks.git" + gem 'database_cleaner' + gem 'spork' + gem 'launchy' + gem 'test-unit' +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..05cd3d0 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,201 @@ +GIT + remote: git://github.com/rspec/rspec-core.git + revision: 001e6004bcaf94674184dc0d87869f060b6990a3 + specs: + rspec-core (2.0.0.beta.20) + +GIT + remote: git://github.com/rspec/rspec-expectations.git + revision: 7cdb347ce0ac06aa8508639f9f674b32a20f0f0e + specs: + rspec-expectations (2.0.0.beta.20) + diff-lcs (>= 1.1.2) + +GIT + remote: git://github.com/rspec/rspec-mocks.git + revision: fee8d4da93b2610dd3dd7996cfcf992cc9455141 + specs: + rspec-mocks (2.0.0.beta.20) + +GIT + remote: git://github.com/rspec/rspec-rails.git + revision: a79dc73358ce050cafd69261e15e63df1b79d0a7 + specs: + rspec-rails (2.0.0.beta.20) + rspec (= 2.0.0.beta.20) + +GIT + remote: git://github.com/rspec/rspec.git + revision: 8f9dfb1ce27a8b2ebd5a91af6b3cfd82a3ad8ec4 + specs: + rspec (2.0.0.beta.20) + rspec-core (= 2.0.0.beta.20) + rspec-expectations (= 2.0.0.beta.20) + rspec-mocks (= 2.0.0.beta.20) + +GIT + remote: git://github.com/rymai/devise_invitable.git + revision: c186969eeb252fc7fac357a1bef9a2242d6108ba + specs: + devise_invitable (0.6.5) + devise (~> 1.1.2) + rails (~> 3.0.0) + +GIT + remote: http://github.com/justinfrench/formtastic.git + revision: eeba8d402721a3b3ae3c6e0d8f1b123fcae96b65 + branch: rails3 + specs: + formtastic (1.1.0.beta) + actionpack (>= 2.3.0) + activesupport (>= 2.3.0) + i18n (>= 0.4.0) + +GEM + remote: http://rubygems.org/ + specs: + abstract (1.0.0) + actionmailer (3.0.0) + actionpack (= 3.0.0) + mail (~> 2.2.5) + actionpack (3.0.0) + activemodel (= 3.0.0) + activesupport (= 3.0.0) + builder (~> 2.1.2) + erubis (~> 2.6.6) + i18n (~> 0.4.1) + rack (~> 1.2.1) + rack-mount (~> 0.6.12) + rack-test (~> 0.5.4) + tzinfo (~> 0.3.23) + activemodel (3.0.0) + activesupport (= 3.0.0) + builder (~> 2.1.2) + i18n (~> 0.4.1) + activerecord (3.0.0) + activemodel (= 3.0.0) + activesupport (= 3.0.0) + arel (~> 1.0.0) + tzinfo (~> 0.3.23) + activeresource (3.0.0) + activemodel (= 3.0.0) + activesupport (= 3.0.0) + activesupport (3.0.0) + arel (1.0.1) + activesupport (~> 3.0.0) + bcrypt-ruby (2.1.2) + builder (2.1.2) + cancan (1.3.4) + capistrano (2.5.19) + highline + net-scp (>= 1.0.0) + net-sftp (>= 2.0.0) + net-ssh (>= 2.0.14) + net-ssh-gateway (>= 1.0.0) + capybara (0.3.9) + culerity (>= 0.2.4) + mime-types (>= 1.16) + nokogiri (>= 1.3.3) + rack (>= 1.0.0) + rack-test (>= 0.5.4) + selenium-webdriver (>= 0.0.3) + configuration (1.1.0) + cucumber (0.8.5) + builder (~> 2.1.2) + diff-lcs (~> 1.1.2) + gherkin (~> 2.1.4) + json_pure (~> 1.4.3) + term-ansicolor (~> 1.0.4) + cucumber-rails (0.3.2) + cucumber (>= 0.8.0) + culerity (0.2.12) + database_cleaner (0.5.2) + devise (1.1.2) + bcrypt-ruby (~> 2.1.2) + warden (~> 0.10.7) + diff-lcs (1.1.2) + erubis (2.6.6) + abstract (>= 1.0.0) + ffi (0.6.3) + rake (>= 0.8.7) + gherkin (2.1.5) + trollop (~> 1.16.2) + highline (1.6.1) + i18n (0.4.1) + json_pure (1.4.6) + launchy (0.3.7) + configuration (>= 0.0.5) + rake (>= 0.8.1) + mail (2.2.5) + activesupport (>= 2.3.6) + mime-types + treetop (>= 1.4.5) + mime-types (1.16) + mysql2 (0.2.3) + net-scp (1.0.3) + net-ssh (>= 1.99.1) + net-sftp (2.0.5) + net-ssh (>= 2.0.9) + net-ssh (2.0.23) + net-ssh-gateway (1.0.1) + net-ssh (>= 1.99.1) + nokogiri (1.4.3.1) + polyglot (0.3.1) + rack (1.2.1) + rack-mount (0.6.13) + rack (>= 1.0.0) + rack-test (0.5.4) + rack (>= 1.0) + rails (3.0.0) + actionmailer (= 3.0.0) + actionpack (= 3.0.0) + activerecord (= 3.0.0) + activeresource (= 3.0.0) + activesupport (= 3.0.0) + bundler (~> 1.0.0) + railties (= 3.0.0) + railties (3.0.0) + actionpack (= 3.0.0) + activesupport (= 3.0.0) + rake (>= 0.8.4) + thor (~> 0.14.0) + rake (0.8.7) + rubyzip (0.9.4) + selenium-webdriver (0.0.28) + ffi (>= 0.6.1) + json_pure + rubyzip + spork (0.8.4) + term-ansicolor (1.0.5) + test-unit (2.1.1) + thor (0.14.0) + treetop (1.4.8) + polyglot (>= 0.3.1) + trollop (1.16.2) + tzinfo (0.3.23) + warden (0.10.7) + rack (>= 1.0.0) + +PLATFORMS + ruby + +DEPENDENCIES + cancan + capistrano + capybara + cucumber + cucumber-rails + database_cleaner + devise (~> 1.1.2) + devise_invitable! + formtastic! + launchy + mysql2 + rails (= 3.0.0) + rspec (>= 2.0.0.beta.20)! + rspec-core (>= 2.0.0.beta.20)! + rspec-expectations (>= 2.0.0.beta.20)! + rspec-mocks (>= 2.0.0.beta.20)! + rspec-rails (>= 2.0.0.beta.20)! + spork + test-unit diff --git a/README b/README new file mode 100644 index 0000000..6966fe9 --- /dev/null +++ b/README @@ -0,0 +1,256 @@ +== Welcome to Rails + +Rails is a web-application framework that includes everything needed to create +database-backed web applications according to the Model-View-Control pattern. + +This pattern splits the view (also called the presentation) into "dumb" +templates that are primarily responsible for inserting pre-built data in between +HTML tags. The model contains the "smart" domain objects (such as Account, +Product, Person, Post) that holds all the business logic and knows how to +persist themselves to a database. The controller handles the incoming requests +(such as Save New Account, Update Product, Show Post) by manipulating the model +and directing data to the view. + +In Rails, the model is handled by what's called an object-relational mapping +layer entitled Active Record. This layer allows you to present the data from +database rows as objects and embellish these data objects with business logic +methods. You can read more about Active Record in +link:files/vendor/rails/activerecord/README.html. + +The controller and view are handled by the Action Pack, which handles both +layers by its two parts: Action View and Action Controller. These two layers +are bundled in a single package due to their heavy interdependence. This is +unlike the relationship between the Active Record and Action Pack that is much +more separate. Each of these packages can be used independently outside of +Rails. You can read more about Action Pack in +link:files/vendor/rails/actionpack/README.html. + + +== Getting Started + +1. At the command prompt, create a new Rails application: + rails new myapp (where myapp is the application name) + +2. Change directory to myapp and start the web server: + cd myapp; rails server (run with --help for options) + +3. Go to http://localhost:3000/ and you'll see: + "Welcome aboard: You're riding Ruby on Rails!" + +4. Follow the guidelines to start developing your application. You can find +the following resources handy: + +* The Getting Started Guide: http://guides.rubyonrails.org/getting_started.html +* Ruby on Rails Tutorial Book: http://www.railstutorial.org/ + + +== Debugging Rails + +Sometimes your application goes wrong. Fortunately there are a lot of tools that +will help you debug it and get it back on the rails. + +First area to check is the application log files. Have "tail -f" commands +running on the server.log and development.log. Rails will automatically display +debugging and runtime information to these files. Debugging info will also be +shown in the browser on requests from 127.0.0.1. + +You can also log your own messages directly into the log file from your code +using the Ruby logger class from inside your controllers. Example: + + class WeblogController < ActionController::Base + def destroy + @weblog = Weblog.find(params[:id]) + @weblog.destroy + logger.info("#{Time.now} Destroyed Weblog ID ##{@weblog.id}!") + end + end + +The result will be a message in your log file along the lines of: + + Mon Oct 08 14:22:29 +1000 2007 Destroyed Weblog ID #1! + +More information on how to use the logger is at http://www.ruby-doc.org/core/ + +Also, Ruby documentation can be found at http://www.ruby-lang.org/. There are +several books available online as well: + +* Programming Ruby: http://www.ruby-doc.org/docs/ProgrammingRuby/ (Pickaxe) +* Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide) + +These two books will bring you up to speed on the Ruby language and also on +programming in general. + + +== Debugger + +Debugger support is available through the debugger command when you start your +Mongrel or WEBrick server with --debugger. This means that you can break out of +execution at any point in the code, investigate and change the model, and then, +resume execution! You need to install ruby-debug to run the server in debugging +mode. With gems, use sudo gem install ruby-debug. Example: + + class WeblogController < ActionController::Base + def index + @posts = Post.find(:all) + debugger + end + end + +So the controller will accept the action, run the first line, then present you +with a IRB prompt in the server window. Here you can do things like: + + >> @posts.inspect + => "[#nil, "body"=>nil, "id"=>"1"}>, + #"Rails", "body"=>"Only ten..", "id"=>"2"}>]" + >> @posts.first.title = "hello from a debugger" + => "hello from a debugger" + +...and even better, you can examine how your runtime objects actually work: + + >> f = @posts.first + => #nil, "body"=>nil, "id"=>"1"}> + >> f. + Display all 152 possibilities? (y or n) + +Finally, when you're ready to resume execution, you can enter "cont". + + +== Console + +The console is a Ruby shell, which allows you to interact with your +application's domain model. Here you'll have all parts of the application +configured, just like it is when the application is running. You can inspect +domain models, change values, and save to the database. Starting the script +without arguments will launch it in the development environment. + +To start the console, run rails console from the application +directory. + +Options: + +* Passing the -s, --sandbox argument will rollback any modifications + made to the database. +* Passing an environment name as an argument will load the corresponding + environment. Example: rails console production. + +To reload your controllers and models after launching the console run +reload! + +More information about irb can be found at: +link:http://www.rubycentral.com/pickaxe/irb.html + + +== dbconsole + +You can go to the command line of your database directly through rails +dbconsole. You would be connected to the database with the credentials +defined in database.yml. Starting the script without arguments will connect you +to the development database. Passing an argument will connect you to a different +database, like rails dbconsole production. Currently works for MySQL, +PostgreSQL and SQLite 3. + +== Description of Contents + +The default directory structure of a generated Ruby on Rails application: + + |-- app + | |-- controllers + | |-- helpers + | |-- models + | `-- views + | `-- layouts + |-- config + | |-- environments + | |-- initializers + | `-- locales + |-- db + |-- doc + |-- lib + | `-- tasks + |-- log + |-- public + | |-- images + | |-- javascripts + | `-- stylesheets + |-- script + | `-- performance + |-- test + | |-- fixtures + | |-- functional + | |-- integration + | |-- performance + | `-- unit + |-- tmp + | |-- cache + | |-- pids + | |-- sessions + | `-- sockets + `-- vendor + `-- plugins + +app + Holds all the code that's specific to this particular application. + +app/controllers + Holds controllers that should be named like weblogs_controller.rb for + automated URL mapping. All controllers should descend from + ApplicationController which itself descends from ActionController::Base. + +app/models + Holds models that should be named like post.rb. Models descend from + ActiveRecord::Base by default. + +app/views + Holds the template files for the view that should be named like + weblogs/index.html.erb for the WeblogsController#index action. All views use + eRuby syntax by default. + +app/views/layouts + Holds the template files for layouts to be used with views. This models the + common header/footer method of wrapping views. In your views, define a layout + using the layout :default and create a file named default.html.erb. + Inside default.html.erb, call <% yield %> to render the view using this + layout. + +app/helpers + Holds view helpers that should be named like weblogs_helper.rb. These are + generated for you automatically when using generators for controllers. + Helpers can be used to wrap functionality for your views into methods. + +config + Configuration files for the Rails environment, the routing map, the database, + and other dependencies. + +db + Contains the database schema in schema.rb. db/migrate contains all the + sequence of Migrations for your schema. + +doc + This directory is where your application documentation will be stored when + generated using rake doc:app + +lib + Application specific libraries. Basically, any kind of custom code that + doesn't belong under controllers, models, or helpers. This directory is in + the load path. + +public + The directory available for the web server. Contains subdirectories for + images, stylesheets, and javascripts. Also contains the dispatchers and the + default HTML files. This should be set as the DOCUMENT_ROOT of your web + server. + +script + Helper scripts for automation and generation. + +test + Unit and functional tests along with fixtures. When using the rails generate + command, template test files will be generated for you and placed in this + directory. + +vendor + External libraries that the application depends on. Also includes the plugins + subdirectory. If the app has frozen rails, those gems also go here, under + vendor/rails/. This directory is in the load path. diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..37fbe07 --- /dev/null +++ b/Rakefile @@ -0,0 +1,7 @@ +# Add your own tasks in files placed in lib/tasks ending in .rake, +# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. + +require File.expand_path('../config/application', __FILE__) +require 'rake' + +UKPortal::Application.load_tasks diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb new file mode 100644 index 0000000..9de0f0e --- /dev/null +++ b/app/controllers/application_controller.rb @@ -0,0 +1,10 @@ +class ApplicationController < ActionController::Base + protect_from_forgery + include SslRequirement + + rescue_from CanCan::AccessDenied do |exception| + flash[:error] = exception.message + redirect_to root_url + end + +end diff --git a/app/controllers/portal_controller.rb b/app/controllers/portal_controller.rb new file mode 100644 index 0000000..bf730b6 --- /dev/null +++ b/app/controllers/portal_controller.rb @@ -0,0 +1,8 @@ +class PortalController < ApplicationController + before_filter :authenticate_user!, :except => [:index] + + + def index + end + +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb new file mode 100644 index 0000000..de6be79 --- /dev/null +++ b/app/helpers/application_helper.rb @@ -0,0 +1,2 @@ +module ApplicationHelper +end diff --git a/app/helpers/portal_helper.rb b/app/helpers/portal_helper.rb new file mode 100644 index 0000000..51f4f8f --- /dev/null +++ b/app/helpers/portal_helper.rb @@ -0,0 +1,2 @@ +module PortalHelper +end diff --git a/app/models/ability.rb b/app/models/ability.rb new file mode 100644 index 0000000..e4eb0c8 --- /dev/null +++ b/app/models/ability.rb @@ -0,0 +1,14 @@ +class Ability + include CanCan::Ability + + def initialise(user) + user ||= User.new #Guest User if not already Set up + if user.role? :super_admin + can :manage, :all + elsif user.role? :location_admin + can :manage, [Location] + else + can :read, :all + end + end +end diff --git a/app/models/role.rb b/app/models/role.rb new file mode 100644 index 0000000..0ade3d4 --- /dev/null +++ b/app/models/role.rb @@ -0,0 +1,4 @@ +class Role < ActiveRecord::Base + has_and_belongs_to_many :users +end + diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..0751749 --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,16 @@ +class User < ActiveRecord::Base + # Include default devise modules. Others available are: + # :token_authenticatable, :confirmable, :lockable and :timeoutable + devise :database_authenticatable, :registerable, + :recoverable, :rememberable, :trackable, :validatable, + :token_authenticatable, :lockable,:timeoutable, :invitable + + # Setup accessible (or protected) attributes for your model + attr_accessible :email, :password, :password_confirmation, :remember_me + + has_and_belongs_to_many :roles + + def role?(role) + return !!self.roles.find_by_name(role.to_s.camelize) + end +end diff --git a/app/views/devise/confirmations/new.html.erb b/app/views/devise/confirmations/new.html.erb new file mode 100644 index 0000000..2dd5a7e --- /dev/null +++ b/app/views/devise/confirmations/new.html.erb @@ -0,0 +1,12 @@ +

Resend confirmation instructions

+ +<%= form_for(resource, :as => resource_name, :url => confirmation_path(resource_name), :html => { :method => :post }) do |f| %> + <%= devise_error_messages! %> + +

<%= f.label :email %>
+ <%= f.text_field :email %>

+ +

<%= f.submit "Resend confirmation instructions" %>

+<% end %> + +<%= render :partial => "devise/shared/links" %> \ No newline at end of file diff --git a/app/views/devise/mailer/confirmation_instructions.html.erb b/app/views/devise/mailer/confirmation_instructions.html.erb new file mode 100644 index 0000000..a6ea8ca --- /dev/null +++ b/app/views/devise/mailer/confirmation_instructions.html.erb @@ -0,0 +1,5 @@ +

Welcome <%= @resource.email %>!

+ +

You can confirm your account through the link below:

+ +

<%= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @resource.confirmation_token) %>

diff --git a/app/views/devise/mailer/reset_password_instructions.html.erb b/app/views/devise/mailer/reset_password_instructions.html.erb new file mode 100644 index 0000000..ae9e888 --- /dev/null +++ b/app/views/devise/mailer/reset_password_instructions.html.erb @@ -0,0 +1,8 @@ +

Hello <%= @resource.email %>!

+ +

Someone has requested a link to change your password, and you can do this through the link below.

+ +

<%= link_to 'Change my password', edit_password_url(@resource, :reset_password_token => @resource.reset_password_token) %>

+ +

If you didn't request this, please ignore this email.

+

Your password won't change until you access the link above and create a new one.

diff --git a/app/views/devise/mailer/unlock_instructions.html.erb b/app/views/devise/mailer/unlock_instructions.html.erb new file mode 100644 index 0000000..2263c21 --- /dev/null +++ b/app/views/devise/mailer/unlock_instructions.html.erb @@ -0,0 +1,7 @@ +

Hello <%= @resource.email %>!

+ +

Your account has been locked due to an excessive amount of unsuccessful sign in attempts.

+ +

Click the link below to unlock your account:

+ +

<%= link_to 'Unlock my account', unlock_url(@resource, :unlock_token => @resource.unlock_token) %>

diff --git a/app/views/devise/passwords/edit.html.erb b/app/views/devise/passwords/edit.html.erb new file mode 100644 index 0000000..b278134 --- /dev/null +++ b/app/views/devise/passwords/edit.html.erb @@ -0,0 +1,16 @@ +

Change your password

+ +<%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :put }) do |f| %> + <%= devise_error_messages! %> + <%= f.hidden_field :reset_password_token %> + +

<%= f.label :password %>
+ <%= f.password_field :password %>

+ +

<%= f.label :password_confirmation %>
+ <%= f.password_field :password_confirmation %>

+ +

<%= f.submit "Change my password" %>

+<% end %> + +<%= render :partial => "devise/shared/links" %> \ No newline at end of file diff --git a/app/views/devise/passwords/new.html.erb b/app/views/devise/passwords/new.html.erb new file mode 100644 index 0000000..b8819f1 --- /dev/null +++ b/app/views/devise/passwords/new.html.erb @@ -0,0 +1,12 @@ +

Forgot your password?

+ +<%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :post }) do |f| %> + <%= devise_error_messages! %> + +

<%= f.label :email %>
+ <%= f.text_field :email %>

+ +

<%= f.submit "Send me reset password instructions" %>

+<% end %> + +<%= render :partial => "devise/shared/links" %> \ No newline at end of file diff --git a/app/views/devise/registrations/edit.html.erb b/app/views/devise/registrations/edit.html.erb new file mode 100644 index 0000000..0f98acb --- /dev/null +++ b/app/views/devise/registrations/edit.html.erb @@ -0,0 +1,25 @@ +

Edit <%= resource_name.to_s.humanize %>

+ +<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %> + <%= devise_error_messages! %> + +

<%= f.label :email %>
+ <%= f.text_field :email %>

+ +

<%= f.label :password %> (leave blank if you don't want to change it)
+ <%= f.password_field :password %>

+ +

<%= f.label :password_confirmation %>
+ <%= f.password_field :password_confirmation %>

+ +

<%= f.label :current_password %> (we need your current password to confirm your changes)
+ <%= f.password_field :current_password %>

+ +

<%= f.submit "Update" %>

+<% end %> + +

Cancel my account

+ +

Unhappy? <%= link_to "Cancel my account", registration_path(resource_name), :confirm => "Are you sure?", :method => :delete %>.

+ +<%= link_to "Back", :back %> diff --git a/app/views/devise/registrations/new.html.erb b/app/views/devise/registrations/new.html.erb new file mode 100644 index 0000000..ae12ee7 --- /dev/null +++ b/app/views/devise/registrations/new.html.erb @@ -0,0 +1,18 @@ +

Sign up

+ +<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %> + <%= devise_error_messages! %> + +

<%= f.label :email %>
+ <%= f.text_field :email %>

+ +

<%= f.label :password %>
+ <%= f.password_field :password %>

+ +

<%= f.label :password_confirmation %>
+ <%= f.password_field :password_confirmation %>

+ +

<%= f.submit "Sign up" %>

+<% end %> + +<%= render :partial => "devise/shared/links" %> diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb new file mode 100644 index 0000000..13902a5 --- /dev/null +++ b/app/views/devise/sessions/new.html.erb @@ -0,0 +1,17 @@ +

Sign in

+ +<%= form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| %> +

<%= f.label :email %>
+ <%= f.text_field :email %>

+ +

<%= f.label :password %>
+ <%= f.password_field :password %>

+ + <% if devise_mapping.rememberable? -%> +

<%= f.check_box :remember_me %> <%= f.label :remember_me %>

+ <% end -%> + +

<%= f.submit "Sign in" %>

+<% end %> + +<%= render :partial => "devise/shared/links" %> \ No newline at end of file diff --git a/app/views/devise/shared/_links.erb b/app/views/devise/shared/_links.erb new file mode 100644 index 0000000..414904b --- /dev/null +++ b/app/views/devise/shared/_links.erb @@ -0,0 +1,19 @@ +<%- if controller_name != 'sessions' %> + <%= link_to "Sign in", new_session_path(resource_name) %>
+<% end -%> + +<%- if devise_mapping.registerable? && controller_name != 'registrations' %> + <%= link_to "Sign up", new_registration_path(resource_name) %>
+<% end -%> + +<%- if devise_mapping.recoverable? && controller_name != 'passwords' %> + <%= link_to "Forgot your password?", new_password_path(resource_name) %>
+<% end -%> + +<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %> + <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %>
+<% end -%> + +<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %> + <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %>
+<% end -%> diff --git a/app/views/devise/unlocks/new.html.erb b/app/views/devise/unlocks/new.html.erb new file mode 100644 index 0000000..a7be7e4 --- /dev/null +++ b/app/views/devise/unlocks/new.html.erb @@ -0,0 +1,12 @@ +

Resend unlock instructions

+ +<%= form_for(resource, :as => resource_name, :url => unlock_path(resource_name), :html => { :method => :post }) do |f| %> + <%= devise_error_messages! %> + +

<%= f.label :email %>
+ <%= f.text_field :email %>

+ +

<%= f.submit "Resend unlock instructions" %>

+<% end %> + +<%= render :partial => "devise/shared/links" %> \ No newline at end of file diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb new file mode 100644 index 0000000..d269d5e --- /dev/null +++ b/app/views/layouts/application.html.erb @@ -0,0 +1,21 @@ + + + + UKPortal + <%= stylesheet_link_tag 'blueprint/screen.css', :media => 'screen,projection' %> + <%= stylesheet_link_tag 'blueprint/print.css', :media => 'print' %> + + <%= javascript_include_tag :defaults %> + <%= csrf_meta_tag %> + + + <% flash.each do |key, value| %> + <%= content_tag :div, value, :id => key %> + <% end %> + +<%= yield %> + + + diff --git a/app/views/portal/index.html.erb b/app/views/portal/index.html.erb new file mode 100644 index 0000000..315a6c7 --- /dev/null +++ b/app/views/portal/index.html.erb @@ -0,0 +1,2 @@ +

Portal#index

+

Find me in app/views/portal/index.html.erb

diff --git a/autotest/discover.rb b/autotest/discover.rb new file mode 100644 index 0000000..f421dc5 --- /dev/null +++ b/autotest/discover.rb @@ -0,0 +1,2 @@ +Autotest.add_discovery { "rails" } +Autotest.add_discovery { "rspec2" } diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..18aa749 --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +# This file is used by Rack-based servers to start the application. + +require ::File.expand_path('../config/environment', __FILE__) +run UKPortal::Application diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..789cf82 --- /dev/null +++ b/config/application.rb @@ -0,0 +1,47 @@ +require File.expand_path('../boot', __FILE__) + +require 'rails/all' + +# If you have a Gemfile, require the gems listed there, including any gems +# you've limited to :test, :development, or :production. +Bundler.require(:default, Rails.env) if defined?(Bundler) + +module UKPortal + class Application < Rails::Application + # Settings in config/environments/* take precedence over those specified here. + # Application configuration should go into files in config/initializers + # -- all .rb files in that directory are automatically loaded. + + # Custom directories with classes and modules you want to be autoloadable. + # config.autoload_paths += %W(#{config.root}/extras) + + # Only load the plugins named here, in the order given (default is alphabetical). + # :all can be used as a placeholder for all plugins not explicitly named. + # config.plugins = [ :exception_notification, :ssl_requirement, :all ] + + # Activate observers that should always be running. + # config.active_record.observers = :cacher, :garbage_collector, :forum_observer + + # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. + # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. + config.time_zone = 'London' + + # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. + # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] + # config.i18n.default_locale = :de + + # JavaScript files you want as :defaults (application.js is always included). + # config.action_view.javascript_expansions[:defaults] = %w(jquery rails) + + # Configure the default encoding used in templates for Ruby 1.9. + config.encoding = "utf-8" + + # Configure sensitive parameters which will be filtered from the log file. + config.filter_parameters += [:password] + + config.generators do |g| + g.test_framework :rspec + end + + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..ab6cb37 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,13 @@ +require 'rubygems' + +# Set up gems listed in the Gemfile. +gemfile = File.expand_path('../../Gemfile', __FILE__) +begin + ENV['BUNDLE_GEMFILE'] = gemfile + require 'bundler' + Bundler.setup +rescue Bundler::GemNotFound => e + STDERR.puts e.message + STDERR.puts "Try running `bundle install`." + exit! +end if File.exist?(gemfile) diff --git a/config/cucumber.yml b/config/cucumber.yml new file mode 100644 index 0000000..621a14c --- /dev/null +++ b/config/cucumber.yml @@ -0,0 +1,8 @@ +<% +rerun = File.file?('rerun.txt') ? IO.read('rerun.txt') : "" +rerun_opts = rerun.to_s.strip.empty? ? "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} features" : "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} #{rerun}" +std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} --strict --tags ~@wip" +%> +default: <%= std_opts %> features +wip: --tags @wip:3 --wip features +rerun: <%= rerun_opts %> --format rerun --out rerun.txt --strict --tags ~@wip diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..f8dbb1d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,42 @@ +# MySQL. Versions 4.1 and 5.0 are recommended. +# +# Install the MySQL driver: +# gem install mysql2 +# +# And be sure to use new-style password hashing: +# http://dev.mysql.com/doc/refman/5.0/en/old-client.html +development: + adapter: mysql2 + encoding: utf8 + reconnect: false + database: UK_Portal_development + pool: 5 + username: root + password: sqldba + socket: /var/run/mysqld/mysqld.sock + +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". +# Do not set this db to the same as development or production. +test: &test + adapter: mysql2 + encoding: utf8 + reconnect: false + database: UK_Portal_test + pool: 5 + username: root + password: sqldba + socket: /var/run/mysqld/mysqld.sock + +production: + adapter: mysql2 + encoding: utf8 + reconnect: false + database: UK_Portal_production + pool: 5 + username: root + password: sqldba + socket: /var/run/mysqld/mysqld.sock + +cucumber: + <<: *test diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..532040a --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,5 @@ +# Load the rails application +require File.expand_path('../application', __FILE__) + +# Initialize the rails application +UKPortal::Application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..56886fd --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,26 @@ +UKPortal::Application.configure do + # Settings specified here will take precedence over those in config/environment.rb + + # In the development environment your application's code is reloaded on + # every request. This slows down response time but is perfect for development + # since you don't have to restart the webserver when you make code changes. + config.cache_classes = false + + # Log error messages when you accidentally call methods on nil. + config.whiny_nils = true + + # Show full error reports and disable caching + config.consider_all_requests_local = true + config.action_view.debug_rjs = true + config.action_controller.perform_caching = false + + # Don't care if the mailer can't send + config.action_mailer.raise_delivery_errors = false + + # Print deprecation notices to the Rails logger + config.active_support.deprecation = :log + + # Only use best-standards-support built into browsers + config.action_dispatch.best_standards_support = :builtin +end + diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..6c6b210 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,49 @@ +UKPortal::Application.configure do + # Settings specified here will take precedence over those in config/environment.rb + + # The production environment is meant for finished, "live" apps. + # Code is not reloaded between requests + config.cache_classes = true + + # Full error reports are disabled and caching is turned on + config.consider_all_requests_local = false + config.action_controller.perform_caching = true + + # Specifies the header that your server uses for sending files + config.action_dispatch.x_sendfile_header = "X-Sendfile" + + # For nginx: + # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' + + # If you have no front-end server that supports something like X-Sendfile, + # just comment this out and Rails will serve the files + + # See everything in the log (default is :info) + # config.log_level = :debug + + # Use a different logger for distributed setups + # config.logger = SyslogLogger.new + + # Use a different cache store in production + # config.cache_store = :mem_cache_store + + # Disable Rails's static asset server + # In production, Apache or nginx will already do this + config.serve_static_assets = false + + # Enable serving of images, stylesheets, and javascripts from an asset server + # config.action_controller.asset_host = "http://assets.example.com" + + # Disable delivery errors, bad email addresses will be ignored + # config.action_mailer.raise_delivery_errors = false + + # Enable threaded mode + # config.threadsafe! + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation can not be found) + config.i18n.fallbacks = true + + # Send deprecation notices to registered listeners + config.active_support.deprecation = :notify +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..9b29a01 --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,35 @@ +UKPortal::Application.configure do + # Settings specified here will take precedence over those in config/environment.rb + + # The test environment is used exclusively to run your application's + # test suite. You never need to work with it otherwise. Remember that + # your test database is "scratch space" for the test suite and is wiped + # and recreated between test runs. Don't rely on the data there! + config.cache_classes = true + + # Log error messages when you accidentally call methods on nil. + config.whiny_nils = true + + # Show full error reports and disable caching + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + + # Raise exceptions instead of rendering exception templates + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment + config.action_controller.allow_forgery_protection = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Use SQL instead of Active Record's schema dumper when creating the test database. + # This is necessary if your schema can't be completely dumped by the schema dumper, + # like if you have constraints or database-specific column types + # config.active_record.schema_format = :sql + + # Print deprecation notices to the stderr + config.active_support.deprecation = :stderr +end diff --git a/config/initializers/backtrace_silencers.rb b/config/initializers/backtrace_silencers.rb new file mode 100644 index 0000000..59385cd --- /dev/null +++ b/config/initializers/backtrace_silencers.rb @@ -0,0 +1,7 @@ +# Be sure to restart your server when you modify this file. + +# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. +# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } + +# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. +# Rails.backtrace_cleaner.remove_silencers! diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb new file mode 100644 index 0000000..db91847 --- /dev/null +++ b/config/initializers/devise.rb @@ -0,0 +1,146 @@ +# Use this hook to configure devise mailer, warden hooks and so forth. The first +# four configuration values can also be set straight in your models. +Devise.setup do |config| + # ==> Mailer Configuration + # Configure the e-mail address which will be shown in DeviseMailer. + config.mailer_sender = "please-change-me@config-initializers-devise.com" + + # Configure the class responsible to send e-mails. + # config.mailer = "Devise::Mailer" + + # ==> ORM configuration + # Load and configure the ORM. Supports :active_record (default) and + # :mongoid (bson_ext recommended) by default. Other ORMs may be + # available as additional gems. + require 'devise/orm/active_record' + + # ==> Configuration for any authentication mechanism + # Configure which keys are used when authenticating an user. By default is + # just :email. You can configure it to use [:username, :subdomain], so for + # authenticating an user, both parameters are required. Remember that those + # parameters are used only when authenticating and not when retrieving from + # session. If you need permissions, you should implement that in a before filter. + # config.authentication_keys = [ :email ] + + # Tell if authentication through request.params is enabled. True by default. + # config.params_authenticatable = true + + # Tell if authentication through HTTP Basic Auth is enabled. True by default. + # config.http_authenticatable = true + + # Set this to true to use Basic Auth for AJAX requests. True by default. + # config.http_authenticatable_on_xhr = true + + # The realm used in Http Basic Authentication + # config.http_authentication_realm = "Application" + + # ==> Configuration for :database_authenticatable + # For bcrypt, this is the cost for hashing the password and defaults to 10. If + # using other encryptors, it sets how many times you want the password re-encrypted. + config.stretches = 10 + + # Define which will be the encryption algorithm. Devise also supports encryptors + # from others authentication tools as :clearance_sha1, :authlogic_sha512 (then + # you should set stretches above to 20 for default behavior) and :restful_authentication_sha1 + # (then you should set stretches to 10, and copy REST_AUTH_SITE_KEY to pepper) + config.encryptor = :bcrypt + + # Setup a pepper to generate the encrypted password. + config.pepper = "f60fe0491f40bc10f9b49a0fb1acd276295043f5221c7760f07db7f1b2aa52b1b3e4bc52be60a7f39fef71337f6fa7892a3891cb59e96d47303987e7e1f4acab" + + # ==> Configuration for :confirmable + # The time you want to give your user to confirm his account. During this time + # he will be able to access your application without confirming. Default is nil. + # When confirm_within is zero, the user won't be able to sign in without confirming. + # You can use this to let your user access some features of your application + # without confirming the account, but blocking it after a certain period + # (ie 2 days). + # config.confirm_within = 2.days + + # ==> Configuration for :rememberable + # The time the user will be remembered without asking for credentials again. + # config.remember_for = 2.weeks + + # If true, a valid remember token can be re-used between multiple browsers. + # config.remember_across_browsers = true + + # If true, extends the user's remember period when remembered via cookie. + # config.extend_remember_period = false + + # ==> Configuration for :validatable + # Range for password length + # config.password_length = 6..20 + + # Regex to use to validate the email address + # config.email_regexp = /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i + + # ==> Configuration for :timeoutable + # The time you want to timeout the user session without activity. After this + # time the user will be asked for credentials again. + # config.timeout_in = 10.minutes + + # ==> Configuration for :lockable + # Defines which strategy will be used to lock an account. + # :failed_attempts = Locks an account after a number of failed attempts to sign in. + # :none = No lock strategy. You should handle locking by yourself. + # config.lock_strategy = :failed_attempts + + # Defines which strategy will be used to unlock an account. + # :email = Sends an unlock link to the user email + # :time = Re-enables login after a certain amount of time (see :unlock_in below) + # :both = Enables both strategies + # :none = No unlock strategy. You should handle unlocking by yourself. + # config.unlock_strategy = :both + + # Number of authentication tries before locking an account if lock_strategy + # is failed attempts. + # config.maximum_attempts = 20 + + # Time interval to unlock the account if :time is enabled as unlock_strategy. + # config.unlock_in = 1.hour + + # ==> Configuration for :token_authenticatable + # Defines name of the authentication token params key + # config.token_authentication_key = :auth_token + + # ==> Scopes configuration + # Turn scoped views on. Before rendering "sessions/new", it will first check for + # "users/sessions/new". It's turned off by default because it's slower if you + # are using only default views. + # config.scoped_views = true + + # Configure the default scope given to Warden. By default it's the first + # devise role declared in your routes. + # config.default_scope = :user + + # Configure sign_out behavior. + # By default sign_out is scoped (i.e. /users/sign_out affects only :user scope). + # In case of sign_out_all_scopes set to true any logout action will sign out all active scopes. + # config.sign_out_all_scopes = false + + # ==> Navigation configuration + # Lists the formats that should be treated as navigational. Formats like + # :html, should redirect to the sign in page when the user does not have + # access, but formats like :xml or :json, should return 401. + # If you have any extra navigational formats, like :iphone or :mobile, you + # should add them to the navigational formats lists. Default is [:html] + # config.navigational_formats = [:html, :iphone] + + + + # ==> Warden configuration + # If you want to use other strategies, that are not (yet) supported by Devise, + # you can configure them inside the config.warden block. The example below + # allows you to setup OAuth, using http://github.com/roman/warden_oauth + # + # config.warden do |manager| + # manager.oauth(:twitter) do |twitter| + # twitter.consumer_secret = + # twitter.consumer_key = + # twitter.options :site => 'http://twitter.com' + # end + # manager.default_strategies(:scope => :user).unshift :twitter_oauth + # end +end + +Devise::SessionsController.ssl_required :new, :create diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..9e8b013 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,10 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format +# (all these examples are active by default): +# ActiveSupport::Inflector.inflections do |inflect| +# inflect.plural /^(ox)$/i, '\1en' +# inflect.singular /^(ox)en/i, '\1' +# inflect.irregular 'person', 'people' +# inflect.uncountable %w( fish sheep ) +# end diff --git a/config/initializers/jquery.rb b/config/initializers/jquery.rb new file mode 100644 index 0000000..1254408 --- /dev/null +++ b/config/initializers/jquery.rb @@ -0,0 +1,12 @@ + # Switch the javascript_include_tag :defaults to + # use jQuery instead of the default prototype helpers. + # Also setup a :jquery expansion, just for good measure. + # Written by: Logan Leger, logan@loganleger.com + # http://github.com/lleger/Rails-3-jQuery + + ActionView::Helpers::AssetTagHelper.register_javascript_expansion :jquery => ['jquery', 'rails'] + ActiveSupport.on_load(:action_view) do + ActiveSupport.on_load(:after_initialize) do + ActionView::Helpers::AssetTagHelper::register_javascript_expansion :defaults => ['jquery', 'rails'] + end + end diff --git a/config/initializers/mime_types.rb b/config/initializers/mime_types.rb new file mode 100644 index 0000000..72aca7e --- /dev/null +++ b/config/initializers/mime_types.rb @@ -0,0 +1,5 @@ +# Be sure to restart your server when you modify this file. + +# Add new mime types for use in respond_to blocks: +# Mime::Type.register "text/richtext", :rtf +# Mime::Type.register_alias "text/html", :iphone diff --git a/config/initializers/secret_token.rb b/config/initializers/secret_token.rb new file mode 100644 index 0000000..77a5f57 --- /dev/null +++ b/config/initializers/secret_token.rb @@ -0,0 +1,7 @@ +# Be sure to restart your server when you modify this file. + +# Your secret key for verifying the integrity of signed cookies. +# If you change this key, all old signed cookies will become invalid! +# Make sure the secret is at least 30 characters and all random, +# no regular words or you'll be exposed to dictionary attacks. +UKPortal::Application.config.secret_token = 'fdfa0679ad6334065cf90316b080dd4c32868689cb5b9da8e776f7ec0ee47dae842f970d7080731cd8c3b36d5b308ee0d66f25180b37dc394ef62dfdc24bcd6b' diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb new file mode 100644 index 0000000..540416b --- /dev/null +++ b/config/initializers/session_store.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +UKPortal::Application.config.session_store :cookie_store, :key => '_UK_Portal_session' + +# Use the database for sessions instead of the cookie-based default, +# which shouldn't be used to store highly confidential information +# (create the session table with "rake db:sessions:create") +# UKPortal::Application.config.session_store :active_record_store diff --git a/config/locales/devise.en.yml b/config/locales/devise.en.yml new file mode 100644 index 0000000..5e4e433 --- /dev/null +++ b/config/locales/devise.en.yml @@ -0,0 +1,39 @@ +en: + errors: + messages: + not_found: "not found" + already_confirmed: "was already confirmed" + not_locked: "was not locked" + + devise: + failure: + unauthenticated: 'You need to sign in or sign up before continuing.' + unconfirmed: 'You have to confirm your account before continuing.' + locked: 'Your account is locked.' + invalid: 'Invalid email or password.' + invalid_token: 'Invalid authentication token.' + timeout: 'Your session expired, please sign in again to continue.' + inactive: 'Your account was not activated yet.' + sessions: + signed_in: 'Signed in successfully.' + signed_out: 'Signed out successfully.' + passwords: + send_instructions: 'You will receive an email with instructions about how to reset your password in a few minutes.' + updated: 'Your password was changed successfully. You are now signed in.' + confirmations: + send_instructions: 'You will receive an email with instructions about how to confirm your account in a few minutes.' + confirmed: 'Your account was successfully confirmed. You are now signed in.' + registrations: + signed_up: 'You have signed up successfully. If enabled, a confirmation was sent to your e-mail.' + updated: 'You updated your account successfully.' + destroyed: 'Bye! Your account was successfully cancelled. We hope to see you again soon.' + unlocks: + send_instructions: 'You will receive an email with instructions about how to unlock your account in a few minutes.' + unlocked: 'Your account was successfully unlocked. You are now signed in.' + mailer: + confirmation_instructions: + subject: 'Confirmation instructions' + reset_password_instructions: + subject: 'Reset password instructions' + unlock_instructions: + subject: 'Unlock Instructions' diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..a747bfa --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,5 @@ +# Sample localization file for English. Add more files in this directory for other locales. +# See http://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. + +en: + hello: "Hello world" diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..ef44241 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,60 @@ +UKPortal::Application.routes.draw do + devise_for :users + + # The priority is based upon order of creation: + # first created -> highest priority. + + # Sample of regular route: + # match 'products/:id' => 'catalog#view' + # Keep in mind you can assign values other than :controller and :action + + # Sample of named route: + # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase + # This route can be invoked with purchase_url(:id => product.id) + + # Sample resource route (maps HTTP verbs to controller actions automatically): + # resources :products + + # Sample resource route with options: + # resources :products do + # member do + # get 'short' + # post 'toggle' + # end + # + # collection do + # get 'sold' + # end + # end + + # Sample resource route with sub-resources: + # resources :products do + # resources :comments, :sales + # resource :seller + # end + + # Sample resource route with more complex sub-resources + # resources :products do + # resources :comments + # resources :sales do + # get 'recent', :on => :collection + # end + # end + + # Sample resource route within a namespace: + # namespace :admin do + # # Directs /admin/products/* to Admin::ProductsController + # # (app/controllers/admin/products_controller.rb) + # resources :products + # end + + # You can have the root of your site routed with "root" + # just remember to delete public/index.html. + root :to => "portal#index" + + # See how all your routes lay out with "rake routes" + + # This is a legacy wild controller route that's not recommended for RESTful applications. + # Note: This route will make all actions in every controller accessible via GET requests. + # match ':controller(/:action(/:id(.:format)))' +end diff --git a/db/migrate/20100901113751_devise_create_users.rb b/db/migrate/20100901113751_devise_create_users.rb new file mode 100644 index 0000000..d383e82 --- /dev/null +++ b/db/migrate/20100901113751_devise_create_users.rb @@ -0,0 +1,26 @@ +class DeviseCreateUsers < ActiveRecord::Migration + def self.up + create_table(:users) do |t| + t.database_authenticatable :null => false + t.recoverable + t.rememberable + t.trackable + + # t.confirmable + t.lockable :lock_strategy => :failed_attempts, :unlock_strategy => :both + t.token_authenticatable + + + t.timestamps + end + + add_index :users, :email, :unique => true + add_index :users, :reset_password_token, :unique => true + # add_index :users, :confirmation_token, :unique => true + add_index :users, :unlock_token, :unique => true + end + + def self.down + drop_table :users + end +end diff --git a/db/migrate/20100901125355_create_cancan_role_migration.rb b/db/migrate/20100901125355_create_cancan_role_migration.rb new file mode 100644 index 0000000..9e0914e --- /dev/null +++ b/db/migrate/20100901125355_create_cancan_role_migration.rb @@ -0,0 +1,12 @@ +class CreateCancanRoleMigration < ActiveRecord::Migration + def self.up + create_table :roles do |t| + t.string :name + t.timestamps + end + end + + def self.down + drop_table :roles + end +end diff --git a/db/migrate/20100901125550_users_have_and_belong_to_many_roles.rb b/db/migrate/20100901125550_users_have_and_belong_to_many_roles.rb new file mode 100644 index 0000000..fbc6c5f --- /dev/null +++ b/db/migrate/20100901125550_users_have_and_belong_to_many_roles.rb @@ -0,0 +1,11 @@ +class UsersHaveAndBelongToManyRoles < ActiveRecord::Migration + def self.up + create_table :roles_users, :id => false do |t| + t.references :role, :user + end + end + + def self.down + drop_table :roles_users + end +end diff --git a/db/migrate/20100901130613_add_invitable_options_to_devise.rb b/db/migrate/20100901130613_add_invitable_options_to_devise.rb new file mode 100644 index 0000000..fbc28e8 --- /dev/null +++ b/db/migrate/20100901130613_add_invitable_options_to_devise.rb @@ -0,0 +1,14 @@ +class AddInvitableOptionsToDevise < ActiveRecord::Migration + def self.up + change_table :users do |t| + t.string :invitation_token, :limit => 20 + t.datetime :invitation_sent_at + t.index :invitation_token + end + change_column :users, :encrypted_password, :string, :null => true + change_column :users, :password_salt, :string, :null => true + end + + def self.down + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..a5eff84 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,53 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# Note that this schema.rb definition is the authoritative source for your +# database schema. If you need to create the application database on another +# system, you should be using db:schema:load, not running all the migrations +# from scratch. The latter is a flawed and unsustainable approach (the more migrations +# you'll amass, the slower it'll run and the greater likelihood for issues). +# +# It's strongly recommended to check this file into your version control system. + +ActiveRecord::Schema.define(:version => 20100901130613) do + + create_table "roles", :force => true do |t| + t.string "name" + t.datetime "created_at" + t.datetime "updated_at" + end + + create_table "roles_users", :id => false, :force => true do |t| + t.integer "role_id" + t.integer "user_id" + end + + create_table "users", :force => true do |t| + t.string "email", :default => "", :null => false + t.string "encrypted_password", :default => "" + t.string "password_salt", :default => "" + t.string "reset_password_token" + t.string "remember_token" + t.datetime "remember_created_at" + t.integer "sign_in_count", :default => 0 + t.datetime "current_sign_in_at" + t.datetime "last_sign_in_at" + t.string "current_sign_in_ip" + t.string "last_sign_in_ip" + t.integer "failed_attempts", :default => 0 + t.string "unlock_token" + t.datetime "locked_at" + t.string "authentication_token" + t.datetime "created_at" + t.datetime "updated_at" + t.string "invitation_token", :limit => 20 + t.datetime "invitation_sent_at" + end + + add_index "users", ["email"], :name => "index_users_on_email", :unique => true + add_index "users", ["invitation_token"], :name => "index_users_on_invitation_token" + add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true + add_index "users", ["unlock_token"], :name => "index_users_on_unlock_token", :unique => true + +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 0000000..664d8c7 --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,7 @@ +# This file should contain all the record creation needed to seed the database with its default values. +# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). +# +# Examples: +# +# cities = City.create([{ :name => 'Chicago' }, { :name => 'Copenhagen' }]) +# Mayor.create(:name => 'Daley', :city => cities.first) diff --git a/doc/README_FOR_APP b/doc/README_FOR_APP new file mode 100644 index 0000000..fe41f5c --- /dev/null +++ b/doc/README_FOR_APP @@ -0,0 +1,2 @@ +Use this README file to introduce your application and point to useful places in the API for learning more. +Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries. diff --git a/features/devise.feature b/features/devise.feature new file mode 100644 index 0000000..9552167 --- /dev/null +++ b/features/devise.feature @@ -0,0 +1,18 @@ +Feature: Test Authentication Functionality + In Order to see if I can log in to my App, I need to register an Account + + Scenario: Creating a new account + Given I am not authenticated + When I go to devise_register + And I fill in "user_email" with "someone@example.com" + And I fill in "user_password" with "Password123" + And I fill in "user_password_confirmation" with "Password123" + And I press "Sign up" + Then I should see "You have signed up successfully" + +#Scenario: Willing to edit my account +# Given I am a new, authenticated user # beyond this step, your work! +# When I want to edit my account +# Then I should see the account initialization form +# And I should see "Your account has not been initialized yet. Do it now!" + diff --git a/features/step_definitions/devise.rb b/features/step_definitions/devise.rb new file mode 100644 index 0000000..5199ebf --- /dev/null +++ b/features/step_definitions/devise.rb @@ -0,0 +1,22 @@ +Given /^I am not authenticated$/ do + visit('/users/sign_out') # ensure that at least +end + +Given /^I have one\s+user "([^\"]*)" with password "([^\"]*)" and login "([^\"]*)"$/ do |email, password, login| + User.new(:email => email, + :login => login, + :password => password, + :password_confirmation => password).save! +end + +Given /^I am a new, authenticated user$/ do + email = 'testing@man.net' + login = 'Testing man' + password = 'secretpass' + + Given %{I have one user "#{email}" with password "#{password}" and login "#{login}"} + And %{I go to login} + And %{I fill in "user_email" with "#{email}"} + And %{I fill in "user_password" with "#{password}"} + And %{I press "Sign in"} +end diff --git a/features/step_definitions/web_steps.rb b/features/step_definitions/web_steps.rb new file mode 100644 index 0000000..0f0af8a --- /dev/null +++ b/features/step_definitions/web_steps.rb @@ -0,0 +1,219 @@ +# IMPORTANT: This file is generated by cucumber-rails - edit at your own peril. +# It is recommended to regenerate this file in the future when you upgrade to a +# newer version of cucumber-rails. Consider adding your own code to a new file +# instead of editing this one. Cucumber will automatically load all features/**/*.rb +# files. + + +require 'uri' +require 'cgi' +require File.expand_path(File.join(File.dirname(__FILE__), "..", "support", "paths")) + +module WithinHelpers + def with_scope(locator) + locator ? within(locator) { yield } : yield + end +end +World(WithinHelpers) + +Given /^(?:|I )am on (.+)$/ do |page_name| + visit path_to(page_name) +end + +When /^(?:|I )go to (.+)$/ do |page_name| + visit path_to(page_name) +end + +When /^(?:|I )press "([^"]*)"(?: within "([^"]*)")?$/ do |button, selector| + with_scope(selector) do + click_button(button) + end +end + +When /^(?:|I )follow "([^"]*)"(?: within "([^"]*)")?$/ do |link, selector| + with_scope(selector) do + click_link(link) + end +end + +When /^(?:|I )fill in "([^"]*)" with "([^"]*)"(?: within "([^"]*)")?$/ do |field, value, selector| + with_scope(selector) do + fill_in(field, :with => value) + end +end + +When /^(?:|I )fill in "([^"]*)" for "([^"]*)"(?: within "([^"]*)")?$/ do |value, field, selector| + with_scope(selector) do + fill_in(field, :with => value) + end +end + +# Use this to fill in an entire form with data from a table. Example: +# +# When I fill in the following: +# | Account Number | 5002 | +# | Expiry date | 2009-11-01 | +# | Note | Nice guy | +# | Wants Email? | | +# +# TODO: Add support for checkbox, select og option +# based on naming conventions. +# +When /^(?:|I )fill in the following(?: within "([^"]*)")?:$/ do |selector, fields| + with_scope(selector) do + fields.rows_hash.each do |name, value| + When %{I fill in "#{name}" with "#{value}"} + end + end +end + +When /^(?:|I )select "([^"]*)" from "([^"]*)"(?: within "([^"]*)")?$/ do |value, field, selector| + with_scope(selector) do + select(value, :from => field) + end +end + +When /^(?:|I )check "([^"]*)"(?: within "([^"]*)")?$/ do |field, selector| + with_scope(selector) do + check(field) + end +end + +When /^(?:|I )uncheck "([^"]*)"(?: within "([^"]*)")?$/ do |field, selector| + with_scope(selector) do + uncheck(field) + end +end + +When /^(?:|I )choose "([^"]*)"(?: within "([^"]*)")?$/ do |field, selector| + with_scope(selector) do + choose(field) + end +end + +When /^(?:|I )attach the file "([^"]*)" to "([^"]*)"(?: within "([^"]*)")?$/ do |path, field, selector| + with_scope(selector) do + attach_file(field, path) + end +end + +Then /^(?:|I )should see JSON:$/ do |expected_json| + require 'json' + expected = JSON.pretty_generate(JSON.parse(expected_json)) + actual = JSON.pretty_generate(JSON.parse(response.body)) + expected.should == actual +end + +Then /^(?:|I )should see "([^"]*)"(?: within "([^"]*)")?$/ do |text, selector| + with_scope(selector) do + if page.respond_to? :should + page.should have_content(text) + else + assert page.has_content?(text) + end + end +end + +Then /^(?:|I )should see \/([^\/]*)\/(?: within "([^"]*)")?$/ do |regexp, selector| + regexp = Regexp.new(regexp) + with_scope(selector) do + if page.respond_to? :should + page.should have_xpath('//*', :text => regexp) + else + assert page.has_xpath?('//*', :text => regexp) + end + end +end + +Then /^(?:|I )should not see "([^"]*)"(?: within "([^"]*)")?$/ do |text, selector| + with_scope(selector) do + if page.respond_to? :should + page.should have_no_content(text) + else + assert page.has_no_content?(text) + end + end +end + +Then /^(?:|I )should not see \/([^\/]*)\/(?: within "([^"]*)")?$/ do |regexp, selector| + regexp = Regexp.new(regexp) + with_scope(selector) do + if page.respond_to? :should + page.should have_no_xpath('//*', :text => regexp) + else + assert page.has_no_xpath?('//*', :text => regexp) + end + end +end + +Then /^the "([^"]*)" field(?: within "([^"]*)")? should contain "([^"]*)"$/ do |field, selector, value| + with_scope(selector) do + field = find_field(field) + field_value = (field.tag_name == 'textarea') ? field.text : field.value + if field_value.respond_to? :should + field_value.should =~ /#{value}/ + else + assert_match(/#{value}/, field_value) + end + end +end + +Then /^the "([^"]*)" field(?: within "([^"]*)")? should not contain "([^"]*)"$/ do |field, selector, value| + with_scope(selector) do + field = find_field(field) + field_value = (field.tag_name == 'textarea') ? field.text : field.value + if field_value.respond_to? :should_not + field_value.should_not =~ /#{value}/ + else + assert_no_match(/#{value}/, field_value) + end + end +end + +Then /^the "([^"]*)" checkbox(?: within "([^"]*)")? should be checked$/ do |label, selector| + with_scope(selector) do + field_checked = find_field(label)['checked'] + if field_checked.respond_to? :should + field_checked.should be_true + else + assert field_checked + end + end +end + +Then /^the "([^"]*)" checkbox(?: within "([^"]*)")? should not be checked$/ do |label, selector| + with_scope(selector) do + field_checked = find_field(label)['checked'] + if field_checked.respond_to? :should + field_checked.should be_false + else + assert !field_checked + end + end +end + +Then /^(?:|I )should be on (.+)$/ do |page_name| + current_path = URI.parse(current_url).path + if current_path.respond_to? :should + current_path.should == path_to(page_name) + else + assert_equal path_to(page_name), current_path + end +end + +Then /^(?:|I )should have the following query string:$/ do |expected_pairs| + query = URI.parse(current_url).query + actual_params = query ? CGI.parse(query) : {} + expected_params = {} + expected_pairs.rows_hash.each_pair{|k,v| expected_params[k] = v.split(',')} + + if actual_params.respond_to? :should + actual_params.should == expected_params + else + assert_equal expected_params, actual_params + end +end + +Then /^show me the page$/ do + save_and_open_page +end diff --git a/features/support/env.rb b/features/support/env.rb new file mode 100644 index 0000000..3333139 --- /dev/null +++ b/features/support/env.rb @@ -0,0 +1,57 @@ +# IMPORTANT: This file is generated by cucumber-rails - edit at your own peril. +# It is recommended to regenerate this file in the future when you upgrade to a +# newer version of cucumber-rails. Consider adding your own code to a new file +# instead of editing this one. Cucumber will automatically load all features/**/*.rb +# files. + +ENV["RAILS_ENV"] ||= "test" +require File.expand_path(File.dirname(__FILE__) + '/../../config/environment') + +require 'cucumber/formatter/unicode' # Remove this line if you don't want Cucumber Unicode support +require 'cucumber/rails/world' +require 'cucumber/rails/active_record' +require 'cucumber/web/tableish' + +require 'capybara/rails' +require 'capybara/cucumber' +require 'capybara/session' +require 'cucumber/rails/capybara_javascript_emulation' # Lets you click links with onclick javascript handlers without using @culerity or @javascript +# Capybara defaults to XPath selectors rather than Webrat's default of CSS3. In +# order to ease the transition to Capybara we set the default here. If you'd +# prefer to use XPath just remove this line and adjust any selectors in your +# steps to use the XPath syntax. +Capybara.default_selector = :css + +# If you set this to false, any error raised from within your app will bubble +# up to your step definition and out to cucumber unless you catch it somewhere +# on the way. You can make Rails rescue errors and render error pages on a +# per-scenario basis by tagging a scenario or feature with the @allow-rescue tag. +# +# If you set this to true, Rails will rescue all errors and render error +# pages, more or less in the same way your application would behave in the +# default production environment. It's not recommended to do this for all +# of your scenarios, as this makes it hard to discover errors in your application. +ActionController::Base.allow_rescue = false + +# If you set this to true, each scenario will run in a database transaction. +# You can still turn off transactions on a per-scenario basis, simply tagging +# a feature or scenario with the @no-txn tag. If you are using Capybara, +# tagging with @culerity or @javascript will also turn transactions off. +# +# If you set this to false, transactions will be off for all scenarios, +# regardless of whether you use @no-txn or not. +# +# Beware that turning transactions off will leave data in your database +# after each scenario, which can lead to hard-to-debug failures in +# subsequent scenarios. If you do this, we recommend you create a Before +# block that will explicitly put your database in a known state. +Cucumber::Rails::World.use_transactional_fixtures = true +# How to clean your database when transactions are turned off. See +# http://github.com/bmabey/database_cleaner for more info. +if defined?(ActiveRecord::Base) + begin + require 'database_cleaner' + DatabaseCleaner.strategy = :truncation + rescue LoadError => ignore_if_database_cleaner_not_present + end +end diff --git a/features/support/paths.rb b/features/support/paths.rb new file mode 100644 index 0000000..e5065d0 --- /dev/null +++ b/features/support/paths.rb @@ -0,0 +1,35 @@ +module NavigationHelpers + # Maps a name to a path. Used by the + # + # When /^I go to (.+)$/ do |page_name| + # + # step definition in web_steps.rb + # + def path_to(page_name) + case page_name + + when /the home\s?page/ + '/' + when /devise_register/ + '/users/sign_up' + + # Add more mappings here. + # Here is an example that pulls values out of the Regexp: + # + # when /^(.*)'s profile page$/i + # user_profile_path(User.find_by_login($1)) + + else + begin + page_name =~ /the (.*) page/ + path_components = $1.split(/\s+/) + self.send(path_components.push('path').join('_').to_sym) + rescue Object => e + raise "Can't find mapping from \"#{page_name}\" to a path.\n" + + "Now, go and add a mapping in #{__FILE__}" + end + end + end +end + +World(NavigationHelpers) diff --git a/lib/tasks/.gitkeep b/lib/tasks/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/lib/tasks/cucumber.rake b/lib/tasks/cucumber.rake new file mode 100644 index 0000000..7db1a55 --- /dev/null +++ b/lib/tasks/cucumber.rake @@ -0,0 +1,53 @@ +# IMPORTANT: This file is generated by cucumber-rails - edit at your own peril. +# It is recommended to regenerate this file in the future when you upgrade to a +# newer version of cucumber-rails. Consider adding your own code to a new file +# instead of editing this one. Cucumber will automatically load all features/**/*.rb +# files. + + +unless ARGV.any? {|a| a =~ /^gems/} # Don't load anything when running the gems:* tasks + +vendored_cucumber_bin = Dir["#{Rails.root}/vendor/{gems,plugins}/cucumber*/bin/cucumber"].first +$LOAD_PATH.unshift(File.dirname(vendored_cucumber_bin) + '/../lib') unless vendored_cucumber_bin.nil? + +begin + require 'cucumber/rake/task' + + namespace :cucumber do + Cucumber::Rake::Task.new({:ok => 'db:test:prepare'}, 'Run features that should pass') do |t| + t.binary = vendored_cucumber_bin # If nil, the gem's binary is used. + t.fork = true # You may get faster startup if you set this to false + t.profile = 'default' + end + + Cucumber::Rake::Task.new({:wip => 'db:test:prepare'}, 'Run features that are being worked on') do |t| + t.binary = vendored_cucumber_bin + t.fork = true # You may get faster startup if you set this to false + t.profile = 'wip' + end + + Cucumber::Rake::Task.new({:rerun => 'db:test:prepare'}, 'Record failing features and run only them if any exist') do |t| + t.binary = vendored_cucumber_bin + t.fork = true # You may get faster startup if you set this to false + t.profile = 'rerun' + end + + desc 'Run all features' + task :all => [:ok, :wip] + end + desc 'Alias for cucumber:ok' + task :cucumber => 'cucumber:ok' + + task :default => :cucumber + + task :features => :cucumber do + STDERR.puts "*** The 'features' task is deprecated. See rake -T cucumber ***" + end +rescue LoadError + desc 'cucumber rake task not available (cucumber not installed)' + task :cucumber do + abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin' + end +end + +end diff --git a/public/404.html b/public/404.html new file mode 100644 index 0000000..9a48320 --- /dev/null +++ b/public/404.html @@ -0,0 +1,26 @@ + + + + The page you were looking for doesn't exist (404) + + + + + +
+

The page you were looking for doesn't exist.

+

You may have mistyped the address or the page may have moved.

+
+ + diff --git a/public/422.html b/public/422.html new file mode 100644 index 0000000..83660ab --- /dev/null +++ b/public/422.html @@ -0,0 +1,26 @@ + + + + The change you wanted was rejected (422) + + + + + +
+

The change you wanted was rejected.

+

Maybe you tried to change something you didn't have access to.

+
+ + diff --git a/public/500.html b/public/500.html new file mode 100644 index 0000000..b80307f --- /dev/null +++ b/public/500.html @@ -0,0 +1,26 @@ + + + + We're sorry, but something went wrong (500) + + + + + +
+

We're sorry, but something went wrong.

+

We've been notified about this issue and we'll take a look at it shortly.

+
+ + diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..e69de29 diff --git a/public/images/rails.png b/public/images/rails.png new file mode 100644 index 0000000000000000000000000000000000000000..d5edc04e65f555e3ba4dcdaad39dc352e75b575e GIT binary patch literal 6646 zcwPba842czP)pVcQya!6@Dsmj@#jv7C*qh zIhOJ6_K0n?*d`*T7TDuW-}m`9Kz3~>+7`DUkbAraU%yi+R{N~~XA2B%zt-4=tLimUer9!2M~N{G5bftFij_O&)a zsHnOppFIzebQ`RA0$!yUM-lg#*o@_O2wf422iLnM6cU(ktYU8#;*G!QGhIy9+ZfzKjLuZo%@a z-i@9A`X%J{^;2q&ZHY3C(B%gqCPW!8{9C0PMcNZccefK){s|V5-xxtHQc@uf>XqhD z7#N^siWqetgq29aX>G^olMf=bbRF6@Y(}zYxw6o!9WBdG1unP}<(V;zKlcR2p86fq zYjaqB^;Ycq>Wy@5T1xOzG3tucG3e%nPvajaN{CrFbnzv^9&K3$NrDm*eQe4`BGQ2bI;dFEwyt>hK%X!L6)82aOZp zsrGcJ#7PoX7)s|~t6is?FfX*7vWdREi58tiY4S)t6u*|kv?J)d_$r+CH#eZ?Ef+I_ z(eVlX8dh~4QP?o*E`_MgaNFIKj*rtN(0Raj3ECjSXcWfd#27NYs&~?t`QZFT}!Zaf=ldZIhi}LhQlqLo+o5(Pvui&{7PD__^53f9j>HW`Q z_V8X5j~$|GP9qXu0C#!@RX2}lXD35@3N5{BkUi%jtaPQ*H6OX2zIz4QPuqmTv3`vG{zc>l3t0B9E75h< z8&twGh%dp7WPNI+tRl%#gf2}Epg8st+~O4GjtwJsXfN;EjAmyr6z5dnaFU(;IV~QK zW62fogF~zA``(Q>_SmD!izc6Y4zq*97|NAPHp1j5X7Op2%;GLYm>^HEMyObo6s7l) zE3n|aOHi5~B84!}b^b*-aL2E)>OEJX_tJ~t<#VJ?bT?lDwyDB&5SZ$_1aUhmAY}#* zs@V1I+c5md9%R-o#_DUfqVtRk>59{+Opd5Yu%dAU#VQW}^m}x-30ftBx#527{^pI4 z6l2C6C7QBG$~NLYb3rVdLD#Z{+SleOp`(Lg5J}`kxdTHe(nV5BdpLrD=l|)e$gEqA zwI6vuX-PFCtcDIH>bGY2dwq&^tf+&R?)nY-@7_j%4CMRAF}C9w%p86W<2!aSY$p+k zrkFtG=cGo38RnrG28;?PNk%7a@faaXq&MS*&?1Z`7Ojw7(#>}ZG4nMAs3VXxfdW>i zY4VX02c5;f7jDPY_7@Oa)CHH}cH<3y#}_!nng^W+h1e-RL*YFYOteC@h?BtJZ+?sE zy)P5^8Mregx{nQaw1NY-|3>{Z)|0`?zc?G2-acYiSU`tj#sSGfm7k86ZQ0SQgPevcklHxM9<~4yW zR796sisf1|!#{Z=e^)0;_8iUhL8g(;j$l=02FTPZ(dZV@s#aQ`DHkLM6=YsbE4iQ!b#*374l0Jw5;jD%J;vQayq=nD8-kHI~f9Ux|32SJUM`> zGp2UGK*4t?cRKi!2he`zI#j0f${I#f-jeT?u_C7S4WsA0)ryi-1L0(@%pa^&g5x=e z=KW9+Nn(=)1T&S8g_ug%dgk*~l2O-$r9#zEGBdQsweO%t*6F4c8JC36JtTizCyy+E4h%G(+ z5>y$%0txMuQ$e~wjFgN(xrAndHQo`Za+K*?gUVDTBV&Ap^}|{w#CIq{DRe}+l@(Ec zCCV6f_?dY_{+f{}6XGn!pL_up?}@>KijT^$w#Lb6iHW&^8RP~g6y=vZBXx~B9nI^i zGexaPjcd(%)zGw!DG_dDwh-7x6+ST#R^${iz_M$uM!da8SxgB_;Z0G%Y*HpvLjKw; zX=ir7i1O$-T|*TBoH$dlW+TLf5j5sep^DlDtkox;Kg{Q%EXWedJq@J@%VAcK)j3y1 zShM!CS#qax;D@RND%2t3W6kv+#Ky0F9<3YKDbV^XJ=^$s(Vtza8V72YY)577nnldI zHMA0PUo!F3j(ubV*CM@PiK<^|RM2(DuCbG7`W}Rg(xdYC>C~ z;1KJGLN&$cRxSZunjXcntykmpFJ7;dk>shY(DdK&3K_JDJ6R%D`e~6Qv67@Rwu+q9 z*|NG{r}4F8f{Dfzt0+cZMd$fvlX3Q`dzM46@r?ISxr;9gBTG2rmfiGOD*#c*3f)cc zF+PFZobY$-^}J8 z%n=h4;x2}cP!@SiVd!v;^Wwo0(N??-ygDr7gG^NKxDjSo{5T{?$|Qo5;8V!~D6O;F*I zuY!gd@+2j_8Rn=UWDa#*4E2auWoGYDddMW7t0=yuC(xLWky?vLimM~!$3fgu!dR>p z?L?!8z>6v$|MsLb&dU?ob)Zd!B)!a*Z2eTE7 zKCzP&e}XO>CT%=o(v+WUY`Az*`9inbTG& z_9_*oQKw;sc8{ipoBC`S4Tb7a%tUE)1fE+~ib$;|(`|4QbXc2>VzFi%1nX%ti;^s3~NIL0R}!!a{0A zyCRp0F7Y&vcP&3`&Dzv5!&#h}F2R-h&QhIfq*ts&qO13{_CP}1*sLz!hI9VoTSzTu zok5pV0+~jrGymE~{TgbS#nN5+*rF7ij)cnSLQw0Ltc70zmk|O!O(kM<3zw-sUvkx~ z2`y+{xAwKSa-0}n7{$I@Zop7CWy%_xIeN1e-7&OjQ6vZZPbZ^3_ z(~=;ZSP98S2oB#35b1~_x`2gWiPdIVddEf`AD9<@c_s)TM;3J$T_l?pr{<7PTgdiy zBc5IGx)g~n=s+Z$RzYCmv8PlJu%gkh^;%mTGMc)UwRINVD~K;`Rl!5@hhGg;y>5qj zq|u-Yf0q_~Y+Mbivkkfa0nAOzB1acnytogsj_m7FB(-FjihMek#GAU4M!iXCgdK8a zjoKm?*|iz7;dHm4$^hh(`Ufl>yb>$hjIA-;>{>C}G0Di%bGvUsJkfLAV|xq32c>RqJqTBJ3Dx zYC;*Dt|S$b6)aCJFnK(Eey$M1DpVV~_MIhwK> zygo(jWC|_IRw|456`roEyXtkNLWNAt-4N1qyN$I@DvBzt;e|?g<*HK1%~cq|^u*}C zmMrwh>{QAq?Ar~4l^DqT%SQ)w)FA(#7#u+N;>E975rYML>)LgE`2<7nN=C1pC{IkV zVw}_&v6j&S?QVh*)wF3#XmE@0($^BVl1969csLKUBNer{suVd!a~B!0MxWY?=(GD6 zy$G&ERFR#i6G4=2F?R4}Mz3B?3tnpoX3)qFF2sh9-Jn*e%9F>i{WG7$_~XyOO2!+@ z6k+38KyD@-0=uee54D0!Z1@B^ilj~StchdOn(*qvg~s5QJpWGc!6U^Aj!xt-HZn_V zS%|fyQ5YS@EP2lBIodXCLjG_+a)%En+7jzngk@J>6D~^xbxKkvf-R0-c%mX+o{?&j zZZ%RxFeav8Y0gkwtdtrwUb-i0Egd2C=ADu%w5VV-hNJvl)GZ?M;y$!?b=S+wKRK7Q zcOjPT!p<*#8m;TsBih=@Xc&c)?Vy`Ys>IvK@|1%N+M6J-^RCRaZcPP2eQh9DEGZr+ z?8B~wF14mk4Xkuen{wY^CWwS1PI<8gikY*)3?RSo5l8es4*J z43k_BIwc}of=6Pfs%xIxlMDGOJN zvl!a>G)52XMqA%fbgkZi%)%bN*ZzZw2!rn4@+J)2eK#kWuEW{)W~-`y1vhA5-7p%R z&f5N!a9f8cK1Xa=O}=9{wg%}Ur^+8Y(!UCeqw>%wj@|bYHD-bZO~mk3L$9_^MmF3G zvCiK^e@q6G?tHkM8%GqsBMZaB20W$UEt_5r~jc#WlR>Bv{6W>A=!#InoY zLOd04@Rz?*7PpW8u|+}bt`?+Z(GsX{Br4A2$ZZ(26Degmr9`O=t2KgHTL*==R3xcP z&Y(J7hC@6_x8zVz!CX3l4Xtss6i7r#E6kXMNN1~>9KTRzewfp))ij%)SBBl0fZdYP zd!zzQD5u8yk-u|41|Rqz7_tCFUMThZJVj)yQf6^Cwtn|Ew6cm5J|u1Bq>MWX-AfB&NE;C z62@=-0le`E6-CurMKjoIy)BuUmhMGJb}pPx!@GLWMT+wH2R?wA=MEy)o57~feFp8P zY@YXAyt4<1FD<|iw{FGQu~GEI<4C64)V*QiVk+VzOV^9GWf4ir#oYgHJz!wq>iZV#_6@_{)&lum)4x z_Of*CLVQ7wdT#XT-(h0qH%mcIF7yzMIvvTN3bPceK>PpJi(=3Nny zbSn}p$dGKQUlX&-t~RR)#F7I<8NCD^yke(vdf#4^aAh}M-{tS9-&^tC4`KU_pToXy z+|K8sx}a)Kh{h{;*V1#hs1xB%(?j>)g~`Wv(9F)f=Qn)(daVB7hZtcp^#LrEr1T1J zZSJ*lVyVVjhy)mkex9Whn=EinKDHe@KlfQI-Fl7M?-c~HnW0;C;+MbUY8?FToy;A+ zs&Nc7VZ=Of+e!G6s#+S5WBU)kgQq_I1@!uH74GJ-+O|%0HXm9Mqlvp|j%0`T>fr9^ zK;qo>XdwZW<>%tTA+<(1^6(>=-2N;hRgBnjvEjN;VbKMbFg--WrGy|XESoH1p|M4` z86(gC^vB4qScASZ&cdpT{~QDN-jC|GJ(RYoW1VW4!SSn- zhQds9&RBKn6M&GVK_Aayt(Hekbnw=tr>f z^o@v9_*iQO1*zeOrts9Q-$pc@!StS&kz$cF`s@pM`rmJXTP&h5G)A74!0e%ZJbl}( zssI|_!%~_hZFypv*S^JE5N&Kvmx7KiG<|fGMO=WrH+@Yhuj+KwiS#l4>@%2nl zS)mDikfmokO4q2A)hRVZBq2-5q&XC>%HOLkOYxZ66(s86?=0s4z5xbiOV)}L-&6b)h6(~CIaR#JNw~46+WBiU7IhB zq!NuR4!TsYnyBg>@G=Ib*cMq^k<}AMpCeYEf&dzfiGI-wOQ7hb+nA zkN7_){y&c3xC0 AQ~&?~ literal 0 HcwPel00001 diff --git a/public/javascripts/application.js b/public/javascripts/application.js new file mode 100644 index 0000000..fe45776 --- /dev/null +++ b/public/javascripts/application.js @@ -0,0 +1,2 @@ +// Place your application-specific JavaScript functions and classes here +// This file is automatically included by javascript_include_tag :defaults diff --git a/public/javascripts/jquery.js b/public/javascripts/jquery.js new file mode 100644 index 0000000..7c24308 --- /dev/null +++ b/public/javascripts/jquery.js @@ -0,0 +1,154 @@ +/*! + * jQuery JavaScript Library v1.4.2 + * http://jquery.com/ + * + * Copyright 2010, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2010, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Sat Feb 13 22:33:48 2010 -0500 + */ +(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(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 X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/, +Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&& +(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this, +a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b=== +"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this, +function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b
a"; +var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected, +parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent= +false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n= +s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true, +applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando]; +else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this, +a,b)})},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 f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b=== +w)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,a)})},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 Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i, +cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(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(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected= +c.inArray(c(this).val(),u)>=0});if(!u.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},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed"); +a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g, +function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split("."); +k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a), +C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B=0){a.type= +e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&& +f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive; +if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data", +e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.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 fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a, +"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a, +d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, +e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift(); +t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D|| +g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m=0))l||m.push(v);else if(l)h[p]=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 h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m, +g);return false}else if(n.match.POS.test(g[0])||n.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===true},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,h,l){return!!k(l[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"===g.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,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return hl[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h= +h[3];l=0;for(m=h.length;l=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m=== +"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g, +h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&& +q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML=""; +if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="

";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}(); +(function(){var g=s.createElement("div");g.innerHTML="
";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}: +function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f0)for(var j=d;j0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j= +{},i;if(f&&a.length){e=0;for(var o=a.length;e-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},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){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},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,2,"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,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType=== +1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===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 Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/"},F={option:[1,""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div
","
"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= +c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).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}, +wrapInner: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)})}, +prepend: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, +this.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,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}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); +return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja, +""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]); +return this}else{e=0;for(var j=d.length;e0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["", +""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]===""&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e= +c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]? +c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja= +function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter= +Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a, +"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f= +a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b= +a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=//gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!== +"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("
").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});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&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).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,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript: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,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},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:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&& +e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)? +"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache=== +false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B= +false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since", +c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E|| +d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x); +g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status=== +1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b=== +"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional; +if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration=== +"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+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);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start; +this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},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;this.custom(this.cur(),0)},step:function(a){var b=J(),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 f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem, +e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,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=c.timers,b=0;b
"; +a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;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.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a, +d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top- +f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset": +"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in +e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window); diff --git a/public/javascripts/rails.js b/public/javascripts/rails.js new file mode 100644 index 0000000..776588a --- /dev/null +++ b/public/javascripts/rails.js @@ -0,0 +1,132 @@ +jQuery(function ($) { + var csrf_token = $('meta[name=csrf-token]').attr('content'), + csrf_param = $('meta[name=csrf-param]').attr('content'); + + $.fn.extend({ + /** + * Triggers a custom event on an element and returns the event result + * this is used to get around not being able to ensure callbacks are placed + * at the end of the chain. + * + * TODO: deprecate with jQuery 1.4.2 release, in favor of subscribing to our + * own events and placing ourselves at the end of the chain. + */ + triggerAndReturn: function (name, data) { + var event = new $.Event(name); + this.trigger(event, data); + + return event.result !== false; + }, + + /** + * Handles execution of remote calls firing overridable events along the way + */ + callRemote: function () { + var el = this, + method = el.attr('method') || el.attr('data-method') || 'GET', + url = el.attr('action') || el.attr('href'), + dataType = el.attr('data-type') || 'script'; + + if (url === undefined) { + throw "No URL specified for remote call (action or href must be present)."; + } else { + if (el.triggerAndReturn('ajax:before')) { + var data = el.is('form') ? el.serializeArray() : []; + $.ajax({ + url: url, + data: data, + dataType: dataType, + type: method.toUpperCase(), + beforeSend: function (xhr) { + el.trigger('ajax:loading', xhr); + }, + success: function (data, status, xhr) { + el.trigger('ajax:success', [data, status, xhr]); + }, + complete: function (xhr) { + el.trigger('ajax:complete', xhr); + }, + error: function (xhr, status, error) { + el.trigger('ajax:failure', [xhr, status, error]); + } + }); + } + + el.trigger('ajax:after'); + } + } + }); + + /** + * confirmation handler + */ + $('a[data-confirm],input[data-confirm]').live('click', function () { + var el = $(this); + if (el.triggerAndReturn('confirm')) { + if (!confirm(el.attr('data-confirm'))) { + return false; + } + } + }); + + + /** + * remote handlers + */ + $('form[data-remote]').live('submit', function (e) { + $(this).callRemote(); + e.preventDefault(); + }); + + $('a[data-remote],input[data-remote]').live('click', function (e) { + $(this).callRemote(); + e.preventDefault(); + }); + + $('a[data-method]:not([data-remote])').live('click', function (e){ + var link = $(this), + href = link.attr('href'), + method = link.attr('data-method'), + form = $('
'), + metadata_input = ''; + + if (csrf_param != null && csrf_token != null) { + metadata_input += ''; + } + + form.hide() + .append(metadata_input) + .appendTo('body'); + + e.preventDefault(); + form.submit(); + }); + + /** + * disable-with handlers + */ + var disable_with_input_selector = 'input[data-disable-with]'; + var disable_with_form_remote_selector = 'form[data-remote]:has(' + disable_with_input_selector + ')'; + var disable_with_form_not_remote_selector = 'form:not([data-remote]):has(' + disable_with_input_selector + ')'; + + var disable_with_input_function = function () { + $(this).find(disable_with_input_selector).each(function () { + var input = $(this); + input.data('enable-with', input.val()) + .attr('value', input.attr('data-disable-with')) + .attr('disabled', 'disabled'); + }); + }; + + $(disable_with_form_remote_selector).live('ajax:before', disable_with_input_function); + $(disable_with_form_not_remote_selector).live('submit', disable_with_input_function); + + $(disable_with_form_remote_selector).live('ajax:complete', function () { + $(this).find(disable_with_input_selector).each(function () { + var input = $(this); + input.removeAttr('disabled') + .val(input.data('enable-with')); + }); + }); + +}); diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..085187f --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,5 @@ +# See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file +# +# To ban all spiders from the entire site uncomment the next two lines: +# User-Agent: * +# Disallow: / diff --git a/public/stylesheets/.gitkeep b/public/stylesheets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/public/stylesheets/blueprint/ie.css b/public/stylesheets/blueprint/ie.css new file mode 100644 index 0000000..3dddda9 --- /dev/null +++ b/public/stylesheets/blueprint/ie.css @@ -0,0 +1,35 @@ +/* ----------------------------------------------------------------------- + + + Blueprint CSS Framework 0.9 + http://blueprintcss.org + + * Copyright (c) 2007-Present. See LICENSE for more info. + * See README for instructions on how to use Blueprint. + * For credits and origins, see AUTHORS. + * This is a compressed file. See the sources in the 'src' directory. + +----------------------------------------------------------------------- */ + +/* ie.css */ +body {text-align:center;} +.container {text-align:left;} +* html .column, * html .span-1, * html .span-2, * html .span-3, * html .span-4, * html .span-5, * html .span-6, * html .span-7, * html .span-8, * html .span-9, * html .span-10, * html .span-11, * html .span-12, * html .span-13, * html .span-14, * html .span-15, * html .span-16, * html .span-17, * html .span-18, * html .span-19, * html .span-20, * html .span-21, * html .span-22, * html .span-23, * html .span-24 {display:inline;overflow-x:hidden;} +* html legend {margin:0px -8px 16px 0;padding:0;} +sup {vertical-align:text-top;} +sub {vertical-align:text-bottom;} +html>body p code {*white-space:normal;} +hr {margin:-8px auto 11px;} +img {-ms-interpolation-mode:bicubic;} +.clearfix, .container {display:inline-block;} +* html .clearfix, * html .container {height:1%;} +fieldset {padding-top:0;} +textarea {overflow:auto;} +input.text, input.title, textarea {background-color:#fff;border:1px solid #bbb;} +input.text:focus, input.title:focus {border-color:#666;} +input.text, input.title, textarea, select {margin:0.5em 0;} +input.checkbox, input.radio {position:relative;top:.25em;} +form.inline div, form.inline p {vertical-align:middle;} +form.inline label {position:relative;top:-0.25em;} +form.inline input.checkbox, form.inline input.radio, form.inline input.button, form.inline button {margin:0.5em 0;} +button, input.button {position:relative;top:0.25em;} \ No newline at end of file diff --git a/public/stylesheets/blueprint/plugins/buttons/icons/cross.png b/public/stylesheets/blueprint/plugins/buttons/icons/cross.png new file mode 100755 index 0000000000000000000000000000000000000000..1514d51a3cf1b67e1c5b9ada36f1fd474e2d214a GIT binary patch literal 655 zcwPaI0&x9_P)uEoyT++I zn$b9r%cFfhHe2K68PkBu*@^<$y+7xQ$wJ~;c5aBx$R=xq*41Wo zhwQus_VOgm0hughj}MhOvs#{>Vg09Y8WxjWUJY5YW zJ?&8eG!59Cz=|E%Ns@013KLWOLV)CObIIj_5{>{#k%TEAMs_GbdDV`x-iYsGH z#=Z{USAQA>NY(}X7=3{K8#4^nI0$7`a(T+P4hBKZ7hk58-_j0w;$<(*=f7ic$nT z*Wgd55in08>183j3?S=MAoDDTLoLSL$!_UDxXqSf-?qdd@H%8(We~hQu&uVIo$6NV z(zMY7wn6r5i617ZGZ)-J($xXssTcN*&WujcIDRIp6J4_PqOvJ}9!p6+yo8LmAGS3~ xN#Qq?aIt$6X#&>gHs{AQG2a)rMyf zFQK~pm1x3+7!nu%-M`k}``c>^00{o_1pjWJUTfl8mg=3qGEl8H@}^@w`VUx0_$uy4 z2FhRqKX}xI*?Tv1DJd8z#F#0c%*~rM30HE1@2o5m~}ZyoWhqv>ql{V z1ZGE0lgcoK^lx+eqc*rAX1Ky;Xx3U%u#zG!m-;eD1Qsn@kf3|F9qz~|95=&g3(7!X zB}JAT>RU;a%vaNOGnJ%e1=K6eAh43c(QN8RQ6~GP%O}Jju$~Ld*%`mO1p and + + + Change Password + + + + Cancel + diff --git a/public/stylesheets/blueprint/plugins/buttons/screen.css b/public/stylesheets/blueprint/plugins/buttons/screen.css new file mode 100644 index 0000000..bb66b21 --- /dev/null +++ b/public/stylesheets/blueprint/plugins/buttons/screen.css @@ -0,0 +1,97 @@ +/* -------------------------------------------------------------- + + buttons.css + * Gives you some great CSS-only buttons. + + Created by Kevin Hale [particletree.com] + * particletree.com/features/rediscovering-the-button-element + + See Readme.txt in this folder for instructions. + +-------------------------------------------------------------- */ + +a.button, button { + display:block; + float:left; + margin: 0.7em 0.5em 0.7em 0; + padding:5px 10px 5px 7px; /* Links */ + + border:1px solid #dedede; + border-top:1px solid #eee; + border-left:1px solid #eee; + + background-color:#f5f5f5; + font-family:"Lucida Grande", Tahoma, Arial, Verdana, sans-serif; + font-size:100%; + line-height:130%; + text-decoration:none; + font-weight:bold; + color:#565656; + cursor:pointer; +} +button { + width:auto; + overflow:visible; + padding:4px 10px 3px 7px; /* IE6 */ +} +button[type] { + padding:4px 10px 4px 7px; /* Firefox */ + line-height:17px; /* Safari */ +} +*:first-child+html button[type] { + padding:4px 10px 3px 7px; /* IE7 */ +} +button img, a.button img{ + margin:0 3px -3px 0 !important; + padding:0; + border:none; + width:16px; + height:16px; + float:none; +} + + +/* Button colors +-------------------------------------------------------------- */ + +/* Standard */ +button:hover, a.button:hover{ + background-color:#dff4ff; + border:1px solid #c2e1ef; + color:#336699; +} +a.button:active{ + background-color:#6299c5; + border:1px solid #6299c5; + color:#fff; +} + +/* Positive */ +body .positive { + color:#529214; +} +a.positive:hover, button.positive:hover { + background-color:#E6EFC2; + border:1px solid #C6D880; + color:#529214; +} +a.positive:active { + background-color:#529214; + border:1px solid #529214; + color:#fff; +} + +/* Negative */ +body .negative { + color:#d12f19; +} +a.negative:hover, button.negative:hover { + background-color:#fbe3e4; + border:1px solid #fbc2c4; + color:#d12f19; +} +a.negative:active { + background-color:#d12f19; + border:1px solid #d12f19; + color:#fff; +} diff --git a/public/stylesheets/blueprint/plugins/fancy-type/readme.txt b/public/stylesheets/blueprint/plugins/fancy-type/readme.txt new file mode 100644 index 0000000..85f2491 --- /dev/null +++ b/public/stylesheets/blueprint/plugins/fancy-type/readme.txt @@ -0,0 +1,14 @@ +Fancy Type + +* Gives you classes to use if you'd like some + extra fancy typography. + +Credits and instructions are specified above each class +in the fancy-type.css file in this directory. + + +Usage +---------------------------------------------------------------- + +1) Add this plugin to lib/settings.yml. + See compress.rb for instructions. diff --git a/public/stylesheets/blueprint/plugins/fancy-type/screen.css b/public/stylesheets/blueprint/plugins/fancy-type/screen.css new file mode 100644 index 0000000..127cf25 --- /dev/null +++ b/public/stylesheets/blueprint/plugins/fancy-type/screen.css @@ -0,0 +1,71 @@ +/* -------------------------------------------------------------- + + fancy-type.css + * Lots of pretty advanced classes for manipulating text. + + See the Readme file in this folder for additional instructions. + +-------------------------------------------------------------- */ + +/* Indentation instead of line shifts for sibling paragraphs. */ + p + p { text-indent:2em; margin-top:-1.5em; } + form p + p { text-indent: 0; } /* Don't want this in forms. */ + + +/* For great looking type, use this code instead of asdf: + asdf + Best used on prepositions and ampersands. */ + +.alt { + color: #666; + font-family: "Warnock Pro", "Goudy Old Style","Palatino","Book Antiqua", Georgia, serif; + font-style: italic; + font-weight: normal; +} + + +/* For great looking quote marks in titles, replace "asdf" with: + asdf” + (That is, when the title starts with a quote mark). + (You may have to change this value depending on your font size). */ + +.dquo { margin-left: -.5em; } + + +/* Reduced size type with incremental leading + (http://www.markboulton.co.uk/journal/comments/incremental_leading/) + + This could be used for side notes. For smaller type, you don't necessarily want to + follow the 1.5x vertical rhythm -- the line-height is too much. + + Using this class, it reduces your font size and line-height so that for + every four lines of normal sized type, there is five lines of the sidenote. eg: + + New type size in em's: + 10px (wanted side note size) / 12px (existing base size) = 0.8333 (new type size in ems) + + New line-height value: + 12px x 1.5 = 18px (old line-height) + 18px x 4 = 72px + 72px / 5 = 14.4px (new line height) + 14.4px / 10px = 1.44 (new line height in em's) */ + +p.incr, .incr p { + font-size: 10px; + line-height: 1.44em; + margin-bottom: 1.5em; +} + + +/* Surround uppercase words and abbreviations with this class. + Based on work by Jørgen Arnor GÃ¥rdsø Lom [http://twistedintellect.com/] */ + +.caps { + font-variant: small-caps; + letter-spacing: 1px; + text-transform: lowercase; + font-size:1.2em; + line-height:1%; + font-weight:bold; + padding:0 2px; +} diff --git a/public/stylesheets/blueprint/plugins/link-icons/icons/doc.png b/public/stylesheets/blueprint/plugins/link-icons/icons/doc.png new file mode 100644 index 0000000000000000000000000000000000000000..834cdfaf48a509ca51d93250fb28dd12e5ea0a13 GIT binary patch literal 777 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 literal 0 HcwPel00001 diff --git a/public/stylesheets/blueprint/plugins/link-icons/icons/feed.png b/public/stylesheets/blueprint/plugins/link-icons/icons/feed.png new file mode 100644 index 0000000000000000000000000000000000000000..315c4f4fa62cb720326ba3f54259666ba3999e42 GIT binary patch literal 691 zcwPas0!;mhP)bpQb1=l6TxbDZwj&S={?7%qx-u`rsG(Zp`-rh=e^=%((1yvsuf5d=&62Zj)Y zH&JviNS_F4_Hj|T(1j4$p-!}kixP9&dB4uv^MveG?dGf%sUCoc2!IFxD6wHRA2^dX zXRVk!-qSfk(jcaUKn#RP48(whfPlJUpApdrA!TQi_4D+fVoM;3I0gZ8{=Xv~Po;geVA+Em9@0Wq2 zr>OTZEGR05L=gf1T;ucCxq6Q6EgJiH@@-lVaAlQyw`jIF^c=&IVnj|95hHbE_cnt| zTzZQ?F4Ne@(bH(~&3nM%m)I@ID{@jJ2qZPjr)jhpe9hViOwH5k&|T#EmmL3(vHeUQ zq^!t^Al6JD;=mHq^Bg?J-8-zG2Od7gZbknG;K9czYjPqG*xjPo0k(c4%lPXTpw(qq z@aGMnxtFS(np+2kC} z7P02O874ZkJH$v#nCUVx$({yDN`IX@o2wyvTD#e`qN`_w5<}$3F+_z1iyEv%?$mbQ(# zwJpuiQJP8?X_`#S8b+U_G6=ziYB!xPAcq{)ZJ0bECH@ zYx#`n8^Wzn^J!4>=q^bltNO15ry?0ecSLkjpT@vlid!jk)Fjf7&)q_V5zGs#3N%6* zbW~7Hg=&P0&~Y(|g>$hC9FL?;ttzPDZbpZu9OLb33^e2;FNTGJxScp1&q4M+y2ntQ z?C(=hpU$3~`Thx0eHwi0x`q+!d5k@|0_WHe%sG3e-s^MM`xM-ig!VcIA7H}X1ot~L zg=MLB4w-Q;Bi!!u2|I+Qb;0{{4Q53YX6+4_aXena{nmt*!YG7ua~`qc>o=?@U?rOU znS7%>klzi*muXnbM6i@4FR@s^8vTjDgy&%J?w?`u>NYMDFa_2%0SQ(qJE<3=<8Bzo zfdU60e*y(^$RF%r$kl)p7=7tlCDa$+J7w>}DU(O#~fk>pYuRvHi1E9^msg{tLeV XM&GIRvfA7%00000NkvXXu0mjf&%8>| literal 0 HcwPel00001 diff --git a/public/stylesheets/blueprint/plugins/link-icons/icons/pdf.png b/public/stylesheets/blueprint/plugins/link-icons/icons/pdf.png new file mode 100644 index 0000000000000000000000000000000000000000..8f8095e46fa4965700afe1f9d065d8a37b101676 GIT binary patch literal 591 zcwPZd0~O9lw>B8WRlD)Gm}Jrz31u-X&&gn2lvjs=i{7nIaL6v2==uw+8Lcs(8j27 z;|c`rmSv@Lx!heopGP^^Ieb3f=R!%Lpp$}iMS-&P3EJ)s48wrJ_Ni0~k|c47D2nj= z{jS6bt|kFpFf|p5cM`_&0Zh|`rfEp0(}=}lT#(6RpzAsUfxv^LSYX>WlAaN$>)*J5 z0#sE+JRUD8iT9*fz{)_^7@6P&!sEjTcD+I9Z4YjT1`wH@fV{cEvneYGFU%maIEU2s55&K(LixD|{p-uiS@?KNj zk-Go8G$hH6g002ovPDHLkV1hVj1#|!a literal 0 HcwPel00001 diff --git a/public/stylesheets/blueprint/plugins/link-icons/icons/visited.png b/public/stylesheets/blueprint/plugins/link-icons/icons/visited.png new file mode 100644 index 0000000000000000000000000000000000000000..ebf206def2729dae1fa9e8c5c9e5a95b7176c45b GIT binary patch literal 46990 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 literal 0 HcwPel00001 diff --git a/public/stylesheets/blueprint/plugins/link-icons/readme.txt b/public/stylesheets/blueprint/plugins/link-icons/readme.txt new file mode 100644 index 0000000..fc4dc64 --- /dev/null +++ b/public/stylesheets/blueprint/plugins/link-icons/readme.txt @@ -0,0 +1,18 @@ +Link Icons +* Icons for links based on protocol or file type. + +This is not supported in IE versions < 7. + + +Credits +---------------------------------------------------------------- + +* Marc Morgan +* Olav Bjorkoy [bjorkoy.com] + + +Usage +---------------------------------------------------------------- + +1) Add this line to your HTML: + diff --git a/public/stylesheets/blueprint/plugins/link-icons/screen.css b/public/stylesheets/blueprint/plugins/link-icons/screen.css new file mode 100644 index 0000000..7b4bef9 --- /dev/null +++ b/public/stylesheets/blueprint/plugins/link-icons/screen.css @@ -0,0 +1,40 @@ +/* -------------------------------------------------------------- + + link-icons.css + * Icons for links based on protocol or file type. + + See the Readme file in this folder for additional instructions. + +-------------------------------------------------------------- */ + +/* Use this class if a link gets an icon when it shouldn't. */ +body a.noicon { + background:transparent none !important; + padding:0 !important; + margin:0 !important; +} + +/* Make sure the icons are not cut */ +a[href^="http:"], a[href^="mailto:"], a[href^="http:"]:visited, +a[href$=".pdf"], a[href$=".doc"], a[href$=".xls"], a[href$=".rss"], +a[href$=".rdf"], a[href^="aim:"] { + padding:2px 22px 2px 0; + margin:-2px 0; + background-repeat: no-repeat; + background-position: right center; +} + +/* External links */ +a[href^="http:"] { background-image: url(icons/external.png); } +a[href^="mailto:"] { background-image: url(icons/email.png); } +a[href^="http:"]:visited { background-image: url(icons/visited.png); } + +/* Files */ +a[href$=".pdf"] { background-image: url(icons/pdf.png); } +a[href$=".doc"] { background-image: url(icons/doc.png); } +a[href$=".xls"] { background-image: url(icons/xls.png); } + +/* Misc */ +a[href$=".rss"], +a[href$=".rdf"] { background-image: url(icons/feed.png); } +a[href^="aim:"] { background-image: url(icons/im.png); } diff --git a/public/stylesheets/blueprint/plugins/rtl/readme.txt b/public/stylesheets/blueprint/plugins/rtl/readme.txt new file mode 100644 index 0000000..5564c40 --- /dev/null +++ b/public/stylesheets/blueprint/plugins/rtl/readme.txt @@ -0,0 +1,10 @@ +RTL +* Mirrors Blueprint, so it can be used with Right-to-Left languages. + +By Ran Yaniv Hartstein, ranh.co.il + +Usage +---------------------------------------------------------------- + +1) Add this line to your HTML: + diff --git a/public/stylesheets/blueprint/plugins/rtl/screen.css b/public/stylesheets/blueprint/plugins/rtl/screen.css new file mode 100644 index 0000000..7db7eb5 --- /dev/null +++ b/public/stylesheets/blueprint/plugins/rtl/screen.css @@ -0,0 +1,110 @@ +/* -------------------------------------------------------------- + + rtl.css + * Mirrors Blueprint for left-to-right languages + + By Ran Yaniv Hartstein [ranh.co.il] + +-------------------------------------------------------------- */ + +body .container { direction: rtl; } +body .column, body .span-1, body .span-2, body .span-3, body .span-4, body .span-5, body .span-6, body .span-7, body .span-8, body .span-9, body .span-10, body .span-11, body .span-12, body .span-13, body .span-14, body .span-15, body .span-16, body .span-17, body .span-18, body .span-19, body .span-20, body .span-21, body .span-22, body .span-23, body .span-24 { + float: right; + margin-right: 0; + margin-left: 10px; + text-align:right; +} + +body div.last { margin-left: 0; } +body table .last { padding-left: 0; } + +body .append-1 { padding-right: 0; padding-left: 40px; } +body .append-2 { padding-right: 0; padding-left: 80px; } +body .append-3 { padding-right: 0; padding-left: 120px; } +body .append-4 { padding-right: 0; padding-left: 160px; } +body .append-5 { padding-right: 0; padding-left: 200px; } +body .append-6 { padding-right: 0; padding-left: 240px; } +body .append-7 { padding-right: 0; padding-left: 280px; } +body .append-8 { padding-right: 0; padding-left: 320px; } +body .append-9 { padding-right: 0; padding-left: 360px; } +body .append-10 { padding-right: 0; padding-left: 400px; } +body .append-11 { padding-right: 0; padding-left: 440px; } +body .append-12 { padding-right: 0; padding-left: 480px; } +body .append-13 { padding-right: 0; padding-left: 520px; } +body .append-14 { padding-right: 0; padding-left: 560px; } +body .append-15 { padding-right: 0; padding-left: 600px; } +body .append-16 { padding-right: 0; padding-left: 640px; } +body .append-17 { padding-right: 0; padding-left: 680px; } +body .append-18 { padding-right: 0; padding-left: 720px; } +body .append-19 { padding-right: 0; padding-left: 760px; } +body .append-20 { padding-right: 0; padding-left: 800px; } +body .append-21 { padding-right: 0; padding-left: 840px; } +body .append-22 { padding-right: 0; padding-left: 880px; } +body .append-23 { padding-right: 0; padding-left: 920px; } + +body .prepend-1 { padding-left: 0; padding-right: 40px; } +body .prepend-2 { padding-left: 0; padding-right: 80px; } +body .prepend-3 { padding-left: 0; padding-right: 120px; } +body .prepend-4 { padding-left: 0; padding-right: 160px; } +body .prepend-5 { padding-left: 0; padding-right: 200px; } +body .prepend-6 { padding-left: 0; padding-right: 240px; } +body .prepend-7 { padding-left: 0; padding-right: 280px; } +body .prepend-8 { padding-left: 0; padding-right: 320px; } +body .prepend-9 { padding-left: 0; padding-right: 360px; } +body .prepend-10 { padding-left: 0; padding-right: 400px; } +body .prepend-11 { padding-left: 0; padding-right: 440px; } +body .prepend-12 { padding-left: 0; padding-right: 480px; } +body .prepend-13 { padding-left: 0; padding-right: 520px; } +body .prepend-14 { padding-left: 0; padding-right: 560px; } +body .prepend-15 { padding-left: 0; padding-right: 600px; } +body .prepend-16 { padding-left: 0; padding-right: 640px; } +body .prepend-17 { padding-left: 0; padding-right: 680px; } +body .prepend-18 { padding-left: 0; padding-right: 720px; } +body .prepend-19 { padding-left: 0; padding-right: 760px; } +body .prepend-20 { padding-left: 0; padding-right: 800px; } +body .prepend-21 { padding-left: 0; padding-right: 840px; } +body .prepend-22 { padding-left: 0; padding-right: 880px; } +body .prepend-23 { padding-left: 0; padding-right: 920px; } + +body .border { + padding-right: 0; + padding-left: 4px; + margin-right: 0; + margin-left: 5px; + border-right: none; + border-left: 1px solid #eee; +} + +body .colborder { + padding-right: 0; + padding-left: 24px; + margin-right: 0; + margin-left: 25px; + border-right: none; + border-left: 1px solid #eee; +} + +body .pull-1 { margin-left: 0; margin-right: -40px; } +body .pull-2 { margin-left: 0; margin-right: -80px; } +body .pull-3 { margin-left: 0; margin-right: -120px; } +body .pull-4 { margin-left: 0; margin-right: -160px; } + +body .push-0 { margin: 0 18px 0 0; } +body .push-1 { margin: 0 18px 0 -40px; } +body .push-2 { margin: 0 18px 0 -80px; } +body .push-3 { margin: 0 18px 0 -120px; } +body .push-4 { margin: 0 18px 0 -160px; } +body .push-0, body .push-1, body .push-2, +body .push-3, body .push-4 { float: left; } + + +/* Typography with RTL support */ +body h1,body h2,body h3, +body h4,body h5,body h6 { font-family: Arial, sans-serif; } +html body { font-family: Arial, sans-serif; } +body pre,body code,body tt { font-family: monospace; } + +/* Mirror floats and margins on typographic elements */ +body p img { float: right; margin: 1.5em 0 1.5em 1.5em; } +body dd, body ul, body ol { margin-left: 0; margin-right: 1.5em;} +body td, body th { text-align:right; } diff --git a/public/stylesheets/blueprint/print.css b/public/stylesheets/blueprint/print.css new file mode 100644 index 0000000..fdb8220 --- /dev/null +++ b/public/stylesheets/blueprint/print.css @@ -0,0 +1,29 @@ +/* ----------------------------------------------------------------------- + + + Blueprint CSS Framework 0.9 + http://blueprintcss.org + + * Copyright (c) 2007-Present. See LICENSE for more info. + * See README for instructions on how to use Blueprint. + * For credits and origins, see AUTHORS. + * This is a compressed file. See the sources in the 'src' directory. + +----------------------------------------------------------------------- */ + +/* print.css */ +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%;} \ No newline at end of file diff --git a/public/stylesheets/blueprint/screen.css b/public/stylesheets/blueprint/screen.css new file mode 100644 index 0000000..46ca92b --- /dev/null +++ b/public/stylesheets/blueprint/screen.css @@ -0,0 +1,258 @@ +/* ----------------------------------------------------------------------- + + + Blueprint CSS Framework 0.9 + http://blueprintcss.org + + * Copyright (c) 2007-Present. See LICENSE for more info. + * See README for instructions on how to use Blueprint. + * For credits and origins, see AUTHORS. + * This is a compressed file. See the sources in the 'src' directory. + +----------------------------------------------------------------------- */ + +/* reset.css */ +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, article, aside, dialog, figure, footer, header, hgroup, nav, section {margin:0;padding:0;border:0;font-weight:inherit;font-style:inherit;font-size:100%;font-family:inherit;vertical-align:baseline;} +article, aside, dialog, figure, footer, header, hgroup, nav, section {display:block;} +body {line-height:1.5;} +table {border-collapse:separate;border-spacing:0;} +caption, th, td {text-align:left;font-weight:normal;} +table, td, th {vertical-align:middle;} +blockquote:before, blockquote:after, q:before, q:after {content:"";} +blockquote, q {quotes:"" "";} +a img {border:none;} + +/* typography.css */ +html {font-size:100.01%;} +body {font-size:75%;color:#222;background:#fff;font-family:"Helvetica Neue", Arial, Helvetica, sans-serif;} +h1, h2, h3, h4, h5, h6 {font-weight:normal;color:#111;} +h1 {font-size:3em;line-height:1;margin-bottom:0.5em;} +h2 {font-size:2em;margin-bottom:0.75em;} +h3 {font-size:1.5em;line-height:1;margin-bottom:1em;} +h4 {font-size:1.2em;line-height:1.25;margin-bottom:1.25em;} +h5 {font-size:1em;font-weight:bold;margin-bottom:1.5em;} +h6 {font-size:1em;font-weight:bold;} +h1 img, h2 img, h3 img, h4 img, h5 img, h6 img {margin:0;} +p {margin:0 0 1.5em;} +p img.left {float:left;margin:1.5em 1.5em 1.5em 0;padding:0;} +p img.right {float:right;margin:1.5em 0 1.5em 1.5em;} +a:focus, a:hover {color:#000;} +a {color:#009;text-decoration:underline;} +blockquote {margin:1.5em;color:#666;font-style:italic;} +strong {font-weight:bold;} +em, dfn {font-style:italic;} +dfn {font-weight:bold;} +sup, sub {line-height:0;} +abbr, acronym {border-bottom:1px dotted #666;} +address {margin:0 0 1.5em;font-style:italic;} +del {color:#666;} +pre {margin:1.5em 0;white-space:pre;} +pre, code, tt {font:1em 'andale mono', 'lucida console', monospace;line-height:1.5;} +li ul, li ol {margin:0;} +ul, ol {margin:0 1.5em 1.5em 0;padding-left:3.333em;} +ul {list-style-type:disc;} +ol {list-style-type:decimal;} +dl {margin:0 0 1.5em 0;} +dl dt {font-weight:bold;} +dd {margin-left:1.5em;} +table {margin-bottom:1.4em;width:100%;} +th {font-weight:bold;} +thead th {background:#c3d9ff;} +th, td, caption {padding:4px 10px 4px 5px;} +tr.even td {background:#e5ecf9;} +tfoot {font-style:italic;} +caption {background:#eee;} +.small {font-size:.8em;margin-bottom:1.875em;line-height:1.875em;} +.large {font-size:1.2em;line-height:2.5em;margin-bottom:1.25em;} +.hide {display:none;} +.quiet {color:#666;} +.loud {color:#000;} +.highlight {background:#ff0;} +.added {background:#060;color:#fff;} +.removed {background:#900;color:#fff;} +.first {margin-left:0;padding-left:0;} +.last {margin-right:0;padding-right:0;} +.top {margin-top:0;padding-top:0;} +.bottom {margin-bottom:0;padding-bottom:0;} + +/* forms.css */ +label {font-weight:bold;} +fieldset {padding:1.4em;margin:0 0 1.5em 0;border:1px solid #ccc;} +legend {font-weight:bold;font-size:1.2em;} +input[type=text], input[type=password], input.text, input.title, textarea, select {background-color:#fff;border:1px solid #bbb;} +input[type=text]:focus, input[type=password]:focus, input.text:focus, input.title:focus, textarea:focus, select:focus {border-color:#666;} +input[type=text], input[type=password], input.text, input.title, textarea, select {margin:0.5em 0;} +input.text, input.title {width:300px;padding:5px;} +input.title {font-size:1.5em;} +textarea {width:390px;height:250px;padding:5px;} +input[type=checkbox], input[type=radio], input.checkbox, input.radio {position:relative;top:.25em;} +form.inline {line-height:3;} +form.inline p {margin-bottom:0;} +.error, .notice, .success {padding:.8em;margin-bottom:1em;border:2px solid #ddd;} +.error {background:#FBE3E4;color:#8a1f11;border-color:#FBC2C4;} +.notice {background:#FFF6BF;color:#514721;border-color:#FFD324;} +.success {background:#E6EFC2;color:#264409;border-color:#C6D880;} +.error a {color:#8a1f11;} +.notice a {color:#514721;} +.success a {color:#264409;} + +/* grid.css */ +.container {width:950px;margin:0 auto;} +.showgrid {background:url(src/grid.png);} +.column, .span-1, .span-2, .span-3, .span-4, .span-5, .span-6, .span-7, .span-8, .span-9, .span-10, .span-11, .span-12, .span-13, .span-14, .span-15, .span-16, .span-17, .span-18, .span-19, .span-20, .span-21, .span-22, .span-23, .span-24 {float:left;margin-right:10px;} +.last {margin-right:0;} +.span-1 {width:30px;} +.span-2 {width:70px;} +.span-3 {width:110px;} +.span-4 {width:150px;} +.span-5 {width:190px;} +.span-6 {width:230px;} +.span-7 {width:270px;} +.span-8 {width:310px;} +.span-9 {width:350px;} +.span-10 {width:390px;} +.span-11 {width:430px;} +.span-12 {width:470px;} +.span-13 {width:510px;} +.span-14 {width:550px;} +.span-15 {width:590px;} +.span-16 {width:630px;} +.span-17 {width:670px;} +.span-18 {width:710px;} +.span-19 {width:750px;} +.span-20 {width:790px;} +.span-21 {width:830px;} +.span-22 {width:870px;} +.span-23 {width:910px;} +.span-24 {width:950px;margin-right:0;} +input.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, input.span-13, textarea.span-13, input.span-14, textarea.span-14, input.span-15, textarea.span-15, input.span-16, textarea.span-16, input.span-17, textarea.span-17, input.span-18, textarea.span-18, input.span-19, textarea.span-19, input.span-20, textarea.span-20, input.span-21, textarea.span-21, input.span-22, textarea.span-22, input.span-23, textarea.span-23, input.span-24, textarea.span-24 {border-left-width:1px;border-right-width:1px;padding-left:5px;padding-right:5px;} +input.span-1, textarea.span-1 {width:18px;} +input.span-2, textarea.span-2 {width:58px;} +input.span-3, textarea.span-3 {width:98px;} +input.span-4, textarea.span-4 {width:138px;} +input.span-5, textarea.span-5 {width:178px;} +input.span-6, textarea.span-6 {width:218px;} +input.span-7, textarea.span-7 {width:258px;} +input.span-8, textarea.span-8 {width:298px;} +input.span-9, textarea.span-9 {width:338px;} +input.span-10, textarea.span-10 {width:378px;} +input.span-11, textarea.span-11 {width:418px;} +input.span-12, textarea.span-12 {width:458px;} +input.span-13, textarea.span-13 {width:498px;} +input.span-14, textarea.span-14 {width:538px;} +input.span-15, textarea.span-15 {width:578px;} +input.span-16, textarea.span-16 {width:618px;} +input.span-17, textarea.span-17 {width:658px;} +input.span-18, textarea.span-18 {width:698px;} +input.span-19, textarea.span-19 {width:738px;} +input.span-20, textarea.span-20 {width:778px;} +input.span-21, textarea.span-21 {width:818px;} +input.span-22, textarea.span-22 {width:858px;} +input.span-23, textarea.span-23 {width:898px;} +input.span-24, textarea.span-24 {width:938px;} +.append-1 {padding-right:40px;} +.append-2 {padding-right:80px;} +.append-3 {padding-right:120px;} +.append-4 {padding-right:160px;} +.append-5 {padding-right:200px;} +.append-6 {padding-right:240px;} +.append-7 {padding-right:280px;} +.append-8 {padding-right:320px;} +.append-9 {padding-right:360px;} +.append-10 {padding-right:400px;} +.append-11 {padding-right:440px;} +.append-12 {padding-right:480px;} +.append-13 {padding-right:520px;} +.append-14 {padding-right:560px;} +.append-15 {padding-right:600px;} +.append-16 {padding-right:640px;} +.append-17 {padding-right:680px;} +.append-18 {padding-right:720px;} +.append-19 {padding-right:760px;} +.append-20 {padding-right:800px;} +.append-21 {padding-right:840px;} +.append-22 {padding-right:880px;} +.append-23 {padding-right:920px;} +.prepend-1 {padding-left:40px;} +.prepend-2 {padding-left:80px;} +.prepend-3 {padding-left:120px;} +.prepend-4 {padding-left:160px;} +.prepend-5 {padding-left:200px;} +.prepend-6 {padding-left:240px;} +.prepend-7 {padding-left:280px;} +.prepend-8 {padding-left:320px;} +.prepend-9 {padding-left:360px;} +.prepend-10 {padding-left:400px;} +.prepend-11 {padding-left:440px;} +.prepend-12 {padding-left:480px;} +.prepend-13 {padding-left:520px;} +.prepend-14 {padding-left:560px;} +.prepend-15 {padding-left:600px;} +.prepend-16 {padding-left:640px;} +.prepend-17 {padding-left:680px;} +.prepend-18 {padding-left:720px;} +.prepend-19 {padding-left:760px;} +.prepend-20 {padding-left:800px;} +.prepend-21 {padding-left:840px;} +.prepend-22 {padding-left:880px;} +.prepend-23 {padding-left:920px;} +.border {padding-right:4px;margin-right:5px;border-right:1px solid #eee;} +.colborder {padding-right:24px;margin-right:25px;border-right:1px solid #eee;} +.pull-1 {margin-left:-40px;} +.pull-2 {margin-left:-80px;} +.pull-3 {margin-left:-120px;} +.pull-4 {margin-left:-160px;} +.pull-5 {margin-left:-200px;} +.pull-6 {margin-left:-240px;} +.pull-7 {margin-left:-280px;} +.pull-8 {margin-left:-320px;} +.pull-9 {margin-left:-360px;} +.pull-10 {margin-left:-400px;} +.pull-11 {margin-left:-440px;} +.pull-12 {margin-left:-480px;} +.pull-13 {margin-left:-520px;} +.pull-14 {margin-left:-560px;} +.pull-15 {margin-left:-600px;} +.pull-16 {margin-left:-640px;} +.pull-17 {margin-left:-680px;} +.pull-18 {margin-left:-720px;} +.pull-19 {margin-left:-760px;} +.pull-20 {margin-left:-800px;} +.pull-21 {margin-left:-840px;} +.pull-22 {margin-left:-880px;} +.pull-23 {margin-left:-920px;} +.pull-24 {margin-left:-960px;} +.pull-1, .pull-2, .pull-3, .pull-4, .pull-5, .pull-6, .pull-7, .pull-8, .pull-9, .pull-10, .pull-11, .pull-12, .pull-13, .pull-14, .pull-15, .pull-16, .pull-17, .pull-18, .pull-19, .pull-20, .pull-21, .pull-22, .pull-23, .pull-24 {float:left;position:relative;} +.push-1 {margin:0 -40px 1.5em 40px;} +.push-2 {margin:0 -80px 1.5em 80px;} +.push-3 {margin:0 -120px 1.5em 120px;} +.push-4 {margin:0 -160px 1.5em 160px;} +.push-5 {margin:0 -200px 1.5em 200px;} +.push-6 {margin:0 -240px 1.5em 240px;} +.push-7 {margin:0 -280px 1.5em 280px;} +.push-8 {margin:0 -320px 1.5em 320px;} +.push-9 {margin:0 -360px 1.5em 360px;} +.push-10 {margin:0 -400px 1.5em 400px;} +.push-11 {margin:0 -440px 1.5em 440px;} +.push-12 {margin:0 -480px 1.5em 480px;} +.push-13 {margin:0 -520px 1.5em 520px;} +.push-14 {margin:0 -560px 1.5em 560px;} +.push-15 {margin:0 -600px 1.5em 600px;} +.push-16 {margin:0 -640px 1.5em 640px;} +.push-17 {margin:0 -680px 1.5em 680px;} +.push-18 {margin:0 -720px 1.5em 720px;} +.push-19 {margin:0 -760px 1.5em 760px;} +.push-20 {margin:0 -800px 1.5em 800px;} +.push-21 {margin:0 -840px 1.5em 840px;} +.push-22 {margin:0 -880px 1.5em 880px;} +.push-23 {margin:0 -920px 1.5em 920px;} +.push-24 {margin:0 -960px 1.5em 960px;} +.push-1, .push-2, .push-3, .push-4, .push-5, .push-6, .push-7, .push-8, .push-9, .push-10, .push-11, .push-12, .push-13, .push-14, .push-15, .push-16, .push-17, .push-18, .push-19, .push-20, .push-21, .push-22, .push-23, .push-24 {float:right;position:relative;} +.prepend-top {margin-top:1.5em;} +.append-bottom {margin-bottom:1.5em;} +.box {padding:1.5em;margin-bottom:1.5em;background:#E5ECF9;} +hr {background:#ddd;color:#ddd;clear:both;float:none;width:100%;height:.1em;margin:0 0 1.45em;border:none;} +hr.space {background:#fff;color:#fff;visibility:hidden;} +.clearfix:after, .container:after {content:"\0020";display:block;height:0;clear:both;visibility:hidden;overflow:hidden;} +.clearfix, .container {display:block;} +.clear {clear:both;} \ No newline at end of file diff --git a/public/stylesheets/blueprint/src/forms.css b/public/stylesheets/blueprint/src/forms.css new file mode 100644 index 0000000..b491134 --- /dev/null +++ b/public/stylesheets/blueprint/src/forms.css @@ -0,0 +1,65 @@ +/* -------------------------------------------------------------- + + forms.css + * Sets up some default styling for forms + * Gives you classes to enhance your forms + + Usage: + * For text fields, use class .title or .text + * For inline forms, use .inline (even when using columns) + +-------------------------------------------------------------- */ + +label { font-weight: bold; } +fieldset { padding:1.4em; margin: 0 0 1.5em 0; border: 1px solid #ccc; } +legend { font-weight: bold; font-size:1.2em; } + + +/* Form fields +-------------------------------------------------------------- */ + +input[type=text], input[type=password], +input.text, input.title, +textarea, select { + background-color:#fff; + border:1px solid #bbb; +} +input[type=text]:focus, input[type=password]:focus, +input.text:focus, input.title:focus, +textarea:focus, select:focus { + border-color:#666; +} + +input[type=text], input[type=password], +input.text, input.title, +textarea, select { + margin:0.5em 0; +} + +input.text, +input.title { width: 300px; padding:5px; } +input.title { font-size:1.5em; } +textarea { width: 390px; height: 250px; padding:5px; } + +input[type=checkbox], input[type=radio], +input.checkbox, input.radio { + position:relative; top:.25em; +} + +form.inline { line-height:3; } +form.inline p { margin-bottom:0; } + + +/* Success, notice and error boxes +-------------------------------------------------------------- */ + +.error, +.notice, +.success { padding: .8em; margin-bottom: 1em; border: 2px solid #ddd; } + +.error { background: #FBE3E4; color: #8a1f11; border-color: #FBC2C4; } +.notice { background: #FFF6BF; color: #514721; border-color: #FFD324; } +.success { background: #E6EFC2; color: #264409; border-color: #C6D880; } +.error a { color: #8a1f11; } +.notice a { color: #514721; } +.success a { color: #264409; } diff --git a/public/stylesheets/blueprint/src/grid.css b/public/stylesheets/blueprint/src/grid.css new file mode 100755 index 0000000..02a9d0c --- /dev/null +++ b/public/stylesheets/blueprint/src/grid.css @@ -0,0 +1,280 @@ +/* -------------------------------------------------------------- + + grid.css + * Sets up an easy-to-use grid of 24 columns. + + By default, the grid is 950px wide, with 24 columns + spanning 30px, and a 10px margin between columns. + + If you need fewer or more columns, namespaces or semantic + element names, use the compressor script (lib/compress.rb) + +-------------------------------------------------------------- */ + +/* A container should group all your columns. */ +.container { + width: 950px; + margin: 0 auto; +} + +/* Use this class on any .span / container to see the grid. */ +.showgrid { + background: url(src/grid.png); +} + + +/* Columns +-------------------------------------------------------------- */ + +/* Sets up basic grid floating and margin. */ +.column, .span-1, .span-2, .span-3, .span-4, .span-5, .span-6, .span-7, .span-8, .span-9, .span-10, .span-11, .span-12, .span-13, .span-14, .span-15, .span-16, .span-17, .span-18, .span-19, .span-20, .span-21, .span-22, .span-23, .span-24 { + float: left; + margin-right: 10px; +} + +/* The last column in a row needs this class. */ +.last { margin-right: 0; } + +/* Use these classes to set the width of a column. */ +.span-1 {width: 30px;} + +.span-2 {width: 70px;} +.span-3 {width: 110px;} +.span-4 {width: 150px;} +.span-5 {width: 190px;} +.span-6 {width: 230px;} +.span-7 {width: 270px;} +.span-8 {width: 310px;} +.span-9 {width: 350px;} +.span-10 {width: 390px;} +.span-11 {width: 430px;} +.span-12 {width: 470px;} +.span-13 {width: 510px;} +.span-14 {width: 550px;} +.span-15 {width: 590px;} +.span-16 {width: 630px;} +.span-17 {width: 670px;} +.span-18 {width: 710px;} +.span-19 {width: 750px;} +.span-20 {width: 790px;} +.span-21 {width: 830px;} +.span-22 {width: 870px;} +.span-23 {width: 910px;} +.span-24 {width:950px; margin-right:0;} + +/* Use these classes to set the width of an input. */ +input.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, input.span-13, textarea.span-13, input.span-14, textarea.span-14, input.span-15, textarea.span-15, input.span-16, textarea.span-16, input.span-17, textarea.span-17, input.span-18, textarea.span-18, input.span-19, textarea.span-19, input.span-20, textarea.span-20, input.span-21, textarea.span-21, input.span-22, textarea.span-22, input.span-23, textarea.span-23, input.span-24, textarea.span-24 { + border-left-width: 1px; + border-right-width: 1px; + padding-left: 5px; + padding-right: 5px; +} + +input.span-1, textarea.span-1 { width: 18px; } +input.span-2, textarea.span-2 { width: 58px; } +input.span-3, textarea.span-3 { width: 98px; } +input.span-4, textarea.span-4 { width: 138px; } +input.span-5, textarea.span-5 { width: 178px; } +input.span-6, textarea.span-6 { width: 218px; } +input.span-7, textarea.span-7 { width: 258px; } +input.span-8, textarea.span-8 { width: 298px; } +input.span-9, textarea.span-9 { width: 338px; } +input.span-10, textarea.span-10 { width: 378px; } +input.span-11, textarea.span-11 { width: 418px; } +input.span-12, textarea.span-12 { width: 458px; } +input.span-13, textarea.span-13 { width: 498px; } +input.span-14, textarea.span-14 { width: 538px; } +input.span-15, textarea.span-15 { width: 578px; } +input.span-16, textarea.span-16 { width: 618px; } +input.span-17, textarea.span-17 { width: 658px; } +input.span-18, textarea.span-18 { width: 698px; } +input.span-19, textarea.span-19 { width: 738px; } +input.span-20, textarea.span-20 { width: 778px; } +input.span-21, textarea.span-21 { width: 818px; } +input.span-22, textarea.span-22 { width: 858px; } +input.span-23, textarea.span-23 { width: 898px; } +input.span-24, textarea.span-24 { width: 938px; } + +/* Add these to a column to append empty cols. */ + +.append-1 { padding-right: 40px;} +.append-2 { padding-right: 80px;} +.append-3 { padding-right: 120px;} +.append-4 { padding-right: 160px;} +.append-5 { padding-right: 200px;} +.append-6 { padding-right: 240px;} +.append-7 { padding-right: 280px;} +.append-8 { padding-right: 320px;} +.append-9 { padding-right: 360px;} +.append-10 { padding-right: 400px;} +.append-11 { padding-right: 440px;} +.append-12 { padding-right: 480px;} +.append-13 { padding-right: 520px;} +.append-14 { padding-right: 560px;} +.append-15 { padding-right: 600px;} +.append-16 { padding-right: 640px;} +.append-17 { padding-right: 680px;} +.append-18 { padding-right: 720px;} +.append-19 { padding-right: 760px;} +.append-20 { padding-right: 800px;} +.append-21 { padding-right: 840px;} +.append-22 { padding-right: 880px;} +.append-23 { padding-right: 920px;} + +/* Add these to a column to prepend empty cols. */ + +.prepend-1 { padding-left: 40px;} +.prepend-2 { padding-left: 80px;} +.prepend-3 { padding-left: 120px;} +.prepend-4 { padding-left: 160px;} +.prepend-5 { padding-left: 200px;} +.prepend-6 { padding-left: 240px;} +.prepend-7 { padding-left: 280px;} +.prepend-8 { padding-left: 320px;} +.prepend-9 { padding-left: 360px;} +.prepend-10 { padding-left: 400px;} +.prepend-11 { padding-left: 440px;} +.prepend-12 { padding-left: 480px;} +.prepend-13 { padding-left: 520px;} +.prepend-14 { padding-left: 560px;} +.prepend-15 { padding-left: 600px;} +.prepend-16 { padding-left: 640px;} +.prepend-17 { padding-left: 680px;} +.prepend-18 { padding-left: 720px;} +.prepend-19 { padding-left: 760px;} +.prepend-20 { padding-left: 800px;} +.prepend-21 { padding-left: 840px;} +.prepend-22 { padding-left: 880px;} +.prepend-23 { padding-left: 920px;} + + +/* Border on right hand side of a column. */ +.border { + padding-right: 4px; + margin-right: 5px; + border-right: 1px solid #eee; +} + +/* Border with more whitespace, spans one column. */ +.colborder { + padding-right: 24px; + margin-right: 25px; + border-right: 1px solid #eee; +} + + +/* Use these classes on an element to push it into the +next column, or to pull it into the previous column. */ + + +.pull-1 { margin-left: -40px; } +.pull-2 { margin-left: -80px; } +.pull-3 { margin-left: -120px; } +.pull-4 { margin-left: -160px; } +.pull-5 { margin-left: -200px; } +.pull-6 { margin-left: -240px; } +.pull-7 { margin-left: -280px; } +.pull-8 { margin-left: -320px; } +.pull-9 { margin-left: -360px; } +.pull-10 { margin-left: -400px; } +.pull-11 { margin-left: -440px; } +.pull-12 { margin-left: -480px; } +.pull-13 { margin-left: -520px; } +.pull-14 { margin-left: -560px; } +.pull-15 { margin-left: -600px; } +.pull-16 { margin-left: -640px; } +.pull-17 { margin-left: -680px; } +.pull-18 { margin-left: -720px; } +.pull-19 { margin-left: -760px; } +.pull-20 { margin-left: -800px; } +.pull-21 { margin-left: -840px; } +.pull-22 { margin-left: -880px; } +.pull-23 { margin-left: -920px; } +.pull-24 { margin-left: -960px; } + +.pull-1, .pull-2, .pull-3, .pull-4, .pull-5, .pull-6, .pull-7, .pull-8, .pull-9, .pull-10, .pull-11, .pull-12, .pull-13, .pull-14, .pull-15, .pull-16, .pull-17, .pull-18, .pull-19, .pull-20, .pull-21, .pull-22, .pull-23, .pull-24 {float: left; position:relative;} + + +.push-1 { margin: 0 -40px 1.5em 40px; } +.push-2 { margin: 0 -80px 1.5em 80px; } +.push-3 { margin: 0 -120px 1.5em 120px; } +.push-4 { margin: 0 -160px 1.5em 160px; } +.push-5 { margin: 0 -200px 1.5em 200px; } +.push-6 { margin: 0 -240px 1.5em 240px; } +.push-7 { margin: 0 -280px 1.5em 280px; } +.push-8 { margin: 0 -320px 1.5em 320px; } +.push-9 { margin: 0 -360px 1.5em 360px; } +.push-10 { margin: 0 -400px 1.5em 400px; } +.push-11 { margin: 0 -440px 1.5em 440px; } +.push-12 { margin: 0 -480px 1.5em 480px; } +.push-13 { margin: 0 -520px 1.5em 520px; } +.push-14 { margin: 0 -560px 1.5em 560px; } +.push-15 { margin: 0 -600px 1.5em 600px; } +.push-16 { margin: 0 -640px 1.5em 640px; } +.push-17 { margin: 0 -680px 1.5em 680px; } +.push-18 { margin: 0 -720px 1.5em 720px; } +.push-19 { margin: 0 -760px 1.5em 760px; } +.push-20 { margin: 0 -800px 1.5em 800px; } +.push-21 { margin: 0 -840px 1.5em 840px; } +.push-22 { margin: 0 -880px 1.5em 880px; } +.push-23 { margin: 0 -920px 1.5em 920px; } +.push-24 { margin: 0 -960px 1.5em 960px; } + +.push-1, .push-2, .push-3, .push-4, .push-5, .push-6, .push-7, .push-8, .push-9, .push-10, .push-11, .push-12, .push-13, .push-14, .push-15, .push-16, .push-17, .push-18, .push-19, .push-20, .push-21, .push-22, .push-23, .push-24 {float: right; position:relative;} + + +/* Misc classes and elements +-------------------------------------------------------------- */ + +/* In case you need to add a gutter above/below an element */ +.prepend-top { + margin-top:1.5em; +} +.append-bottom { + margin-bottom:1.5em; +} + +/* Use a .box to create a padded box inside a column. */ +.box { + padding: 1.5em; + margin-bottom: 1.5em; + background: #E5ECF9; +} + +/* Use this to create a horizontal ruler across a column. */ +hr { + background: #ddd; + color: #ddd; + clear: both; + float: none; + width: 100%; + height: .1em; + margin: 0 0 1.45em; + border: none; +} + +hr.space { + background: #fff; + color: #fff; + visibility: hidden; +} + + +/* Clearing floats without extra markup + Based on How To Clear Floats Without Structural Markup by PiE + [http://www.positioniseverything.net/easyclearing.html] */ + +.clearfix:after, .container:after { + content: "\0020"; + display: block; + height: 0; + clear: both; + visibility: hidden; + overflow:hidden; +} +.clearfix, .container {display: block;} + +/* Regular clearing + apply to column that should drop below previous ones. */ + +.clear { clear:both; } diff --git a/public/stylesheets/blueprint/src/grid.png b/public/stylesheets/blueprint/src/grid.png new file mode 100644 index 0000000000000000000000000000000000000000..d42a6c32c173bf067ee9fe1aa062afd915fb366c GIT binary patch literal 195 zcwXxa@N?(olHy`uVBq!ia0vp^8bB;0zy>5M`yHMFDYhhUcbETQz!~xV4p4-%z$3C4 zNPB>>+sSM@AS2n+#W5t}@Y@R;c@HQE9K9f5$RPVWzg=TNdlOHhh{)0WhV|C%K~?jM z*S=OS^3yz4TmAiI`@VAx6Brelo!DAbody p code { *white-space: normal; } + +/* IE 6&7 has problems with setting proper
margins. */ +hr { margin:-8px auto 11px; } + +/* Explicitly set interpolation, allowing dynamically resized images to not look horrible */ +img { -ms-interpolation-mode:bicubic; } + +/* Clearing +-------------------------------------------------------------- */ + +/* Makes clearfix actually work in IE */ +.clearfix, .container { display:inline-block; } +* html .clearfix, +* html .container { height:1%; } + + +/* Forms +-------------------------------------------------------------- */ + +/* Fixes padding on fieldset */ +fieldset { padding-top:0; } + +/* Makes classic textareas in IE 6 resemble other browsers */ +textarea { overflow:auto; } + +/* Fixes rule that IE 6 ignores */ +input.text, input.title, textarea { background-color:#fff; border:1px solid #bbb; } +input.text:focus, input.title:focus { border-color:#666; } +input.text, input.title, textarea, select { margin:0.5em 0; } +input.checkbox, input.radio { position:relative; top:.25em; } + +/* Fixes alignment of inline form elements */ +form.inline div, form.inline p { vertical-align:middle; } +form.inline label { position:relative;top:-0.25em; } +form.inline input.checkbox, form.inline input.radio, +form.inline input.button, form.inline button { + margin:0.5em 0; +} +button, input.button { position:relative;top:0.25em; } diff --git a/public/stylesheets/blueprint/src/print.css b/public/stylesheets/blueprint/src/print.css new file mode 100755 index 0000000..bbc7948 --- /dev/null +++ b/public/stylesheets/blueprint/src/print.css @@ -0,0 +1,85 @@ +/* -------------------------------------------------------------- + + print.css + * Gives you some sensible styles for printing pages. + * See Readme file in this directory for further instructions. + + Some additions you'll want to make, customized to your markup: + #header, #footer, #navigation { display:none; } + +-------------------------------------------------------------- */ + +body { + line-height: 1.5; + font-family: "Helvetica Neue", Arial, Helvetica, sans-serif; + color:#000; + background: none; + font-size: 10pt; +} + + +/* Layout +-------------------------------------------------------------- */ + +.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; +} + + +/* Text +-------------------------------------------------------------- */ + +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; } + + +/* Links +-------------------------------------------------------------- */ + +a:link, a:visited { + background: transparent; + font-weight:700; + text-decoration: underline; +} + +a:link:after, a:visited:after { + content: " (" attr(href) ")"; + font-size: 90%; +} + +/* If you're having trouble printing relative links, uncomment and customize this: + (note: This is valid CSS3, but it still won't go through the W3C CSS Validator) */ + +/* a[href^="/"]:after { + content: " (http://www.yourdomain.com" attr(href) ") "; +} */ diff --git a/public/stylesheets/blueprint/src/reset.css b/public/stylesheets/blueprint/src/reset.css new file mode 100755 index 0000000..09d9131 --- /dev/null +++ b/public/stylesheets/blueprint/src/reset.css @@ -0,0 +1,45 @@ +/* -------------------------------------------------------------- + + reset.css + * Resets default browser CSS. + +-------------------------------------------------------------- */ + +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, +article, aside, dialog, figure, footer, header, +hgroup, nav, section { + margin: 0; + padding: 0; + border: 0; + font-weight: inherit; + font-style: inherit; + font-size: 100%; + font-family: inherit; + vertical-align: baseline; +} + +article, aside, dialog, figure, footer, header, +hgroup, nav, section { + display:block; +} + +body { + line-height: 1.5; +} + +/* Tables still need 'cellspacing="0"' in the markup. */ +table { border-collapse: separate; border-spacing: 0; } +caption, th, td { text-align: left; font-weight: normal; } +table, td, th { vertical-align: middle; } + +/* Remove possible quote marks (") from ,
. */ +blockquote:before, blockquote:after, q:before, q:after { content: ""; } +blockquote, q { quotes: "" ""; } + +/* Remove annoying border on linked images. */ +a img { border: none; } diff --git a/public/stylesheets/blueprint/src/typography.css b/public/stylesheets/blueprint/src/typography.css new file mode 100644 index 0000000..a1cfe27 --- /dev/null +++ b/public/stylesheets/blueprint/src/typography.css @@ -0,0 +1,106 @@ +/* -------------------------------------------------------------- + + typography.css + * Sets up some sensible default typography. + +-------------------------------------------------------------- */ + +/* Default font settings. + The font-size percentage is of 16px. (0.75 * 16px = 12px) */ +html { font-size:100.01%; } +body { + font-size: 75%; + color: #222; + background: #fff; + font-family: "Helvetica Neue", Arial, Helvetica, sans-serif; +} + + +/* Headings +-------------------------------------------------------------- */ + +h1,h2,h3,h4,h5,h6 { font-weight: normal; color: #111; } + +h1 { font-size: 3em; line-height: 1; margin-bottom: 0.5em; } +h2 { font-size: 2em; margin-bottom: 0.75em; } +h3 { font-size: 1.5em; line-height: 1; margin-bottom: 1em; } +h4 { font-size: 1.2em; line-height: 1.25; margin-bottom: 1.25em; } +h5 { font-size: 1em; font-weight: bold; margin-bottom: 1.5em; } +h6 { font-size: 1em; font-weight: bold; } + +h1 img, h2 img, h3 img, +h4 img, h5 img, h6 img { + margin: 0; +} + + +/* Text elements +-------------------------------------------------------------- */ + +p { margin: 0 0 1.5em; } +p img.left { float: left; margin: 1.5em 1.5em 1.5em 0; padding: 0; } +p img.right { float: right; margin: 1.5em 0 1.5em 1.5em; } + +a:focus, +a:hover { color: #000; } +a { color: #009; text-decoration: underline; } + +blockquote { margin: 1.5em; color: #666; font-style: italic; } +strong { font-weight: bold; } +em,dfn { font-style: italic; } +dfn { font-weight: bold; } +sup, sub { line-height: 0; } + +abbr, +acronym { border-bottom: 1px dotted #666; } +address { margin: 0 0 1.5em; font-style: italic; } +del { color:#666; } + +pre { margin: 1.5em 0; white-space: pre; } +pre,code,tt { font: 1em 'andale mono', 'lucida console', monospace; line-height: 1.5; } + + +/* Lists +-------------------------------------------------------------- */ + +li ul, +li ol { margin: 0; } +ul, ol { margin: 0 1.5em 1.5em 0; padding-left: 3.333em; } + +ul { list-style-type: disc; } +ol { list-style-type: decimal; } + +dl { margin: 0 0 1.5em 0; } +dl dt { font-weight: bold; } +dd { margin-left: 1.5em;} + + +/* Tables +-------------------------------------------------------------- */ + +table { margin-bottom: 1.4em; width:100%; } +th { font-weight: bold; } +thead th { background: #c3d9ff; } +th,td,caption { padding: 4px 10px 4px 5px; } +tr.even td { background: #e5ecf9; } +tfoot { font-style: italic; } +caption { background: #eee; } + + +/* Misc classes +-------------------------------------------------------------- */ + +.small { font-size: .8em; margin-bottom: 1.875em; line-height: 1.875em; } +.large { font-size: 1.2em; line-height: 2.5em; margin-bottom: 1.25em; } +.hide { display: none; } + +.quiet { color: #666; } +.loud { color: #000; } +.highlight { background:#ff0; } +.added { background:#060; color: #fff; } +.removed { background:#900; color: #fff; } + +.first { margin-left:0; padding-left:0; } +.last { margin-right:0; padding-right:0; } +.top { margin-top:0; padding-top:0; } +.bottom { margin-bottom:0; padding-bottom:0; } diff --git a/script/cucumber b/script/cucumber new file mode 100755 index 0000000..7fa5c92 --- /dev/null +++ b/script/cucumber @@ -0,0 +1,10 @@ +#!/usr/bin/env ruby + +vendored_cucumber_bin = Dir["#{File.dirname(__FILE__)}/../vendor/{gems,plugins}/cucumber*/bin/cucumber"].first +if vendored_cucumber_bin + load File.expand_path(vendored_cucumber_bin) +else + require 'rubygems' unless ENV['NO_RUBYGEMS'] + require 'cucumber' + load Cucumber::BINARY +end diff --git a/script/rails b/script/rails new file mode 100755 index 0000000..f8da2cf --- /dev/null +++ b/script/rails @@ -0,0 +1,6 @@ +#!/usr/bin/env ruby +# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. + +APP_PATH = File.expand_path('../../config/application', __FILE__) +require File.expand_path('../../config/boot', __FILE__) +require 'rails/commands' diff --git a/spec/controllers/portal_controller_spec.rb b/spec/controllers/portal_controller_spec.rb new file mode 100644 index 0000000..b9fb5d2 --- /dev/null +++ b/spec/controllers/portal_controller_spec.rb @@ -0,0 +1,12 @@ +require 'spec_helper' + +describe PortalController do + + describe "GET 'index'" do + it "should be successful" do + get 'index' + response.should be_success + end + end + +end diff --git a/spec/helpers/portal_helper_spec.rb b/spec/helpers/portal_helper_spec.rb new file mode 100644 index 0000000..5d555eb --- /dev/null +++ b/spec/helpers/portal_helper_spec.rb @@ -0,0 +1,15 @@ +require 'spec_helper' + +# Specs in this file have access to a helper object that includes +# the PortalHelper. For example: +# +# describe PortalHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# helper.concat_strings("this","that").should == "this that" +# end +# end +# end +describe PortalHelper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb new file mode 100644 index 0000000..44032b4 --- /dev/null +++ b/spec/models/user_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe User do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..9ff3f65 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,26 @@ +# This file is copied to spec/ when you run 'rails generate rspec:install' +ENV["RAILS_ENV"] ||= 'test' +require File.expand_path("../../config/environment", __FILE__) +require 'rspec/rails' + +# Requires supporting ruby files with custom matchers and macros, etc, +# in spec/support/ and its subdirectories. +Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f} + +RSpec.configure do |config| + # == Mock Framework + # + # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line: + # + # config.mock_with :mocha + # config.mock_with :flexmock + # config.mock_with :rr + config.mock_with :rspec + + config.fixture_path = "#{::Rails.root}/spec/fixtures" + + # If you're not using ActiveRecord, or you'd prefer not to run each of your + # examples within a transaction, comment the following line or assign false + # instead of true. + config.use_transactional_fixtures = true +end diff --git a/spec/views/portal/index.html.erb_spec.rb b/spec/views/portal/index.html.erb_spec.rb new file mode 100644 index 0000000..51f5efc --- /dev/null +++ b/spec/views/portal/index.html.erb_spec.rb @@ -0,0 +1,2 @@ +require 'spec_helper' + diff --git a/vendor/plugins/.gitkeep b/vendor/plugins/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/vendor/plugins/ssl_requirement/README b/vendor/plugins/ssl_requirement/README new file mode 100644 index 0000000..afe5a84 --- /dev/null +++ b/vendor/plugins/ssl_requirement/README @@ -0,0 +1,43 @@ +SSL Requirement +=============== + +SSL requirement adds a declarative way of specifying that certain actions +should only be allowed to run under SSL, and if they're accessed without it, +they should be redirected. + +Example: + + class ApplicationController < ActiveRecord::Base + include SslRequirement + end + + class AccountController < ApplicationController + ssl_required :signup, :payment + ssl_allowed :index + + def signup + # Non-SSL access will be redirected to SSL + end + + def payment + # Non-SSL access will be redirected to SSL + end + + def index + # This action will work either with or without SSL + end + + def other + # SSL access will be redirected to non-SSL + end + end + +You can overwrite the protected method ssl_required? to rely on other things +than just the declarative specification. Say, only premium accounts get SSL. + +P.S.: Beware when you include the SslRequirement module. At the time of +inclusion, it'll add the before_filter that validates the declarations. Some +times you'll want to run other before_filters before that. They should then be +declared ahead of including this module. + +Copyright (c) 2005 David Heinemeier Hansson, released under the MIT license \ No newline at end of file diff --git a/vendor/plugins/ssl_requirement/lib/ssl_requirement.rb b/vendor/plugins/ssl_requirement/lib/ssl_requirement.rb new file mode 100644 index 0000000..dd4a345 --- /dev/null +++ b/vendor/plugins/ssl_requirement/lib/ssl_requirement.rb @@ -0,0 +1,62 @@ +# Copyright (c) 2005 David Heinemeier Hansson +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +module SslRequirement + def self.included(controller) + controller.extend(ClassMethods) + controller.before_filter(:ensure_proper_protocol) + end + + module ClassMethods + # Specifies that the named actions requires an SSL connection to be performed (which is enforced by ensure_proper_protocol). + def ssl_required(*actions) + write_inheritable_array(:ssl_required_actions, actions) + end + + def ssl_allowed(*actions) + write_inheritable_array(:ssl_allowed_actions, actions) + end + end + + protected + # Returns true if the current action is supposed to run as SSL + def ssl_required? + (self.class.read_inheritable_attribute(:ssl_required_actions) || []).include?(action_name.to_sym) + end + + def ssl_allowed? + (self.class.read_inheritable_attribute(:ssl_allowed_actions) || []).include?(action_name.to_sym) + end + + private + def ensure_proper_protocol + return true if ssl_allowed? + + if ssl_required? && !request.ssl? + redirect_to "https://" + request.host + request.request_uri + flash.keep + return false + elsif request.ssl? && !ssl_required? + redirect_to "http://" + request.host + request.request_uri + flash.keep + return false + end + end +end \ No newline at end of file diff --git a/vendor/plugins/ssl_requirement/test/ssl_requirement_test.rb b/vendor/plugins/ssl_requirement/test/ssl_requirement_test.rb new file mode 100644 index 0000000..0dc67ed --- /dev/null +++ b/vendor/plugins/ssl_requirement/test/ssl_requirement_test.rb @@ -0,0 +1,132 @@ +begin + require 'action_controller' +rescue LoadError + if ENV['ACTIONCONTROLLER_PATH'].nil? + abort < true + end + + def b + render :nothing => true + end + + def c + render :nothing => true + end + + def d + render :nothing => true + end + + def set_flash + flash[:foo] = "bar" + end +end + +class SslRequirementTest < Test::Unit::TestCase + def setup + @controller = SslRequirementController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + end + + def test_redirect_to_https_preserves_flash + get :set_flash + get :b + assert_response :redirect + assert_equal "bar", flash[:foo] + end + + def test_not_redirecting_to_https_does_not_preserve_the_flash + get :set_flash + get :d + assert_response :success + assert_nil flash[:foo] + end + + def test_redirect_to_http_preserves_flash + get :set_flash + @request.env['HTTPS'] = "on" + get :d + assert_response :redirect + assert_equal "bar", flash[:foo] + end + + def test_not_redirecting_to_http_does_not_preserve_the_flash + get :set_flash + @request.env['HTTPS'] = "on" + get :a + assert_response :success + assert_nil flash[:foo] + end + + def test_required_without_ssl + assert_not_equal "on", @request.env["HTTPS"] + get :a + assert_response :redirect + assert_match %r{^https://}, @response.headers['Location'] + get :b + assert_response :redirect + assert_match %r{^https://}, @response.headers['Location'] + end + + def test_required_with_ssl + @request.env['HTTPS'] = "on" + get :a + assert_response :success + get :b + assert_response :success + end + + def test_disallowed_without_ssl + assert_not_equal "on", @request.env["HTTPS"] + get :d + assert_response :success + end + + def test_disallowed_with_ssl + @request.env['HTTPS'] = "on" + get :d + assert_response :redirect + assert_match %r{^http://}, @response.headers['Location'] + end + + def test_allowed_without_ssl + assert_not_equal "on", @request.env["HTTPS"] + get :c + assert_response :success + end + + def test_allowed_with_ssl + @request.env['HTTPS'] = "on" + get :c + assert_response :success + end +end \ No newline at end of file -- 2.11.4.GIT