aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/rails-2.0.2/railties
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/rails-2.0.2/railties')
-rw-r--r--vendor/rails-2.0.2/railties/CHANGELOG1899
-rw-r--r--vendor/rails-2.0.2/railties/MIT-LICENSE20
-rw-r--r--vendor/rails-2.0.2/railties/README203
-rw-r--r--vendor/rails-2.0.2/railties/Rakefile358
-rw-r--r--vendor/rails-2.0.2/railties/bin/about3
-rw-r--r--vendor/rails-2.0.2/railties/bin/console3
-rw-r--r--vendor/rails-2.0.2/railties/bin/destroy3
-rw-r--r--vendor/rails-2.0.2/railties/bin/generate3
-rw-r--r--vendor/rails-2.0.2/railties/bin/performance/benchmarker3
-rw-r--r--vendor/rails-2.0.2/railties/bin/performance/profiler3
-rw-r--r--vendor/rails-2.0.2/railties/bin/performance/request3
-rw-r--r--vendor/rails-2.0.2/railties/bin/plugin3
-rw-r--r--vendor/rails-2.0.2/railties/bin/process/inspector3
-rw-r--r--vendor/rails-2.0.2/railties/bin/process/reaper3
-rw-r--r--vendor/rails-2.0.2/railties/bin/process/spawner3
-rwxr-xr-xvendor/rails-2.0.2/railties/bin/rails19
-rw-r--r--vendor/rails-2.0.2/railties/bin/runner3
-rw-r--r--vendor/rails-2.0.2/railties/bin/server3
-rw-r--r--vendor/rails-2.0.2/railties/builtin/rails_info/rails/info.rb123
-rw-r--r--vendor/rails-2.0.2/railties/builtin/rails_info/rails/info_controller.rb9
-rw-r--r--vendor/rails-2.0.2/railties/builtin/rails_info/rails/info_helper.rb2
-rw-r--r--vendor/rails-2.0.2/railties/builtin/rails_info/rails_info_controller.rb2
-rwxr-xr-xvendor/rails-2.0.2/railties/configs/apache.conf40
-rw-r--r--vendor/rails-2.0.2/railties/configs/databases/frontbase.yml28
-rw-r--r--vendor/rails-2.0.2/railties/configs/databases/mysql.yml54
-rw-r--r--vendor/rails-2.0.2/railties/configs/databases/oracle.yml39
-rw-r--r--vendor/rails-2.0.2/railties/configs/databases/postgresql.yml48
-rw-r--r--vendor/rails-2.0.2/railties/configs/databases/sqlite2.yml16
-rw-r--r--vendor/rails-2.0.2/railties/configs/databases/sqlite3.yml19
-rw-r--r--vendor/rails-2.0.2/railties/configs/empty.log0
-rw-r--r--vendor/rails-2.0.2/railties/configs/initializers/inflections.rb10
-rw-r--r--vendor/rails-2.0.2/railties/configs/initializers/mime_types.rb5
-rw-r--r--vendor/rails-2.0.2/railties/configs/lighttpd.conf54
-rw-r--r--vendor/rails-2.0.2/railties/configs/routes.rb35
-rwxr-xr-xvendor/rails-2.0.2/railties/dispatches/dispatch.fcgi24
-rwxr-xr-xvendor/rails-2.0.2/railties/dispatches/dispatch.rb10
-rw-r--r--vendor/rails-2.0.2/railties/dispatches/gateway.cgi97
-rw-r--r--vendor/rails-2.0.2/railties/doc/README_FOR_APP2
-rw-r--r--vendor/rails-2.0.2/railties/environments/boot.rb109
-rw-r--r--vendor/rails-2.0.2/railties/environments/development.rb18
-rw-r--r--vendor/rails-2.0.2/railties/environments/environment.rb59
-rw-r--r--vendor/rails-2.0.2/railties/environments/production.rb19
-rw-r--r--vendor/rails-2.0.2/railties/environments/test.rb22
-rwxr-xr-xvendor/rails-2.0.2/railties/fresh_rakefile10
-rw-r--r--vendor/rails-2.0.2/railties/helpers/application.rb10
-rw-r--r--vendor/rails-2.0.2/railties/helpers/application_helper.rb3
-rw-r--r--vendor/rails-2.0.2/railties/helpers/test_helper.rb38
-rw-r--r--vendor/rails-2.0.2/railties/html/404.html30
-rw-r--r--vendor/rails-2.0.2/railties/html/422.html30
-rw-r--r--vendor/rails-2.0.2/railties/html/500.html30
-rw-r--r--vendor/rails-2.0.2/railties/html/favicon.ico0
-rw-r--r--vendor/rails-2.0.2/railties/html/images/rails.pngbin0 -> 1787 bytes
-rw-r--r--vendor/rails-2.0.2/railties/html/index.html277
-rw-r--r--vendor/rails-2.0.2/railties/html/javascripts/application.js2
-rw-r--r--vendor/rails-2.0.2/railties/html/javascripts/controls.js963
-rw-r--r--vendor/rails-2.0.2/railties/html/javascripts/dragdrop.js972
-rw-r--r--vendor/rails-2.0.2/railties/html/javascripts/effects.js1120
-rw-r--r--vendor/rails-2.0.2/railties/html/javascripts/prototype.js4225
-rw-r--r--vendor/rails-2.0.2/railties/html/robots.txt5
-rw-r--r--vendor/rails-2.0.2/railties/lib/code_statistics.rb107
-rw-r--r--vendor/rails-2.0.2/railties/lib/commands.rb17
-rw-r--r--vendor/rails-2.0.2/railties/lib/commands/about.rb2
-rw-r--r--vendor/rails-2.0.2/railties/lib/commands/console.rb32
-rw-r--r--vendor/rails-2.0.2/railties/lib/commands/destroy.rb6
-rwxr-xr-xvendor/rails-2.0.2/railties/lib/commands/generate.rb6
-rw-r--r--vendor/rails-2.0.2/railties/lib/commands/ncgi/listener86
-rw-r--r--vendor/rails-2.0.2/railties/lib/commands/ncgi/tracker69
-rw-r--r--vendor/rails-2.0.2/railties/lib/commands/performance/benchmarker.rb24
-rw-r--r--vendor/rails-2.0.2/railties/lib/commands/performance/profiler.rb50
-rwxr-xr-xvendor/rails-2.0.2/railties/lib/commands/performance/request.rb6
-rw-r--r--vendor/rails-2.0.2/railties/lib/commands/plugin.rb923
-rw-r--r--vendor/rails-2.0.2/railties/lib/commands/process/inspector.rb68
-rw-r--r--vendor/rails-2.0.2/railties/lib/commands/process/reaper.rb149
-rw-r--r--vendor/rails-2.0.2/railties/lib/commands/process/spawner.rb219
-rw-r--r--vendor/rails-2.0.2/railties/lib/commands/process/spinner.rb57
-rw-r--r--vendor/rails-2.0.2/railties/lib/commands/runner.rb48
-rw-r--r--vendor/rails-2.0.2/railties/lib/commands/server.rb39
-rw-r--r--vendor/rails-2.0.2/railties/lib/commands/servers/base.rb31
-rw-r--r--vendor/rails-2.0.2/railties/lib/commands/servers/lighttpd.rb94
-rw-r--r--vendor/rails-2.0.2/railties/lib/commands/servers/mongrel.rb69
-rw-r--r--vendor/rails-2.0.2/railties/lib/commands/servers/webrick.rb66
-rw-r--r--vendor/rails-2.0.2/railties/lib/commands/update.rb4
-rw-r--r--vendor/rails-2.0.2/railties/lib/console_app.rb30
-rw-r--r--vendor/rails-2.0.2/railties/lib/console_sandbox.rb6
-rw-r--r--vendor/rails-2.0.2/railties/lib/console_with_helpers.rb26
-rw-r--r--vendor/rails-2.0.2/railties/lib/dispatcher.rb24
-rw-r--r--vendor/rails-2.0.2/railties/lib/fcgi_handler.rb223
-rw-r--r--vendor/rails-2.0.2/railties/lib/initializer.rb682
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails/plugin.rb84
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails/plugin/loader.rb150
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails/plugin/locator.rb78
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails/version.rb9
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator.rb43
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/base.rb263
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/commands.rb591
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generated_attribute.rb42
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/applications/app/USAGE9
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/applications/app/app_generator.rb179
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/controller/USAGE29
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/controller/controller_generator.rb37
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/controller/templates/controller.rb10
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/controller/templates/functional_test.rb8
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/controller/templates/helper.rb2
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/controller/templates/view.html.erb2
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/integration_test/USAGE8
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/integration_test/integration_test_generator.rb16
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/integration_test/templates/integration_test.rb10
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/mailer/USAGE16
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/mailer/mailer_generator.rb34
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/mailer/templates/fixture.erb3
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/mailer/templates/fixture.rhtml0
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/mailer/templates/mailer.rb13
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/mailer/templates/unit_test.rb21
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/mailer/templates/view.erb3
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/mailer/templates/view.rhtml0
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/migration/USAGE29
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/migration/migration_generator.rb20
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/migration/templates/migration.rb11
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/model/USAGE27
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/model/model_generator.rb45
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/model/templates/fixtures.yml19
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/model/templates/migration.rb16
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/model/templates/model.rb2
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/model/templates/unit_test.rb8
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/observer/USAGE13
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/observer/observer_generator.rb16
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/observer/templates/observer.rb2
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/observer/templates/unit_test.rb8
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/USAGE25
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/plugin_generator.rb39
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/MIT-LICENSE20
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/README13
-rwxr-xr-xvendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/Rakefile22
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/USAGE8
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/generator.rb8
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/init.rb1
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/install.rb1
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/plugin.rb1
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/tasks.rake4
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/uninstall.rb1
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/unit_test.rb8
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/resource/USAGE23
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/resource/resource_generator.rb74
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/resource/templates/controller.rb2
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/resource/templates/functional_test.rb8
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/resource/templates/helper.rb2
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/USAGE25
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb92
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/controller.rb85
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb45
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/helper.rb2
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/layout.html.erb17
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/style.css74
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/view_edit.html.erb19
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/view_index.html.erb24
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/view_new.html.erb18
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/view_show.html.erb10
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/session_migration/USAGE10
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/session_migration/session_migration_generator.rb18
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/session_migration/templates/migration.rb16
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/lookup.rb244
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/manifest.rb53
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/options.rb143
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/scripts.rb86
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/scripts/destroy.rb30
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/scripts/generate.rb7
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/scripts/update.rb12
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/secret_key_generator.rb160
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/simple_logger.rb46
-rw-r--r--vendor/rails-2.0.2/railties/lib/rails_generator/spec.rb44
-rw-r--r--vendor/rails-2.0.2/railties/lib/railties_path.rb1
-rw-r--r--vendor/rails-2.0.2/railties/lib/ruby_version_check.rb17
-rw-r--r--vendor/rails-2.0.2/railties/lib/rubyprof_ext.rb35
-rw-r--r--vendor/rails-2.0.2/railties/lib/source_annotation_extractor.rb62
-rw-r--r--vendor/rails-2.0.2/railties/lib/tasks/annotations.rake23
-rw-r--r--vendor/rails-2.0.2/railties/lib/tasks/databases.rake363
-rw-r--r--vendor/rails-2.0.2/railties/lib/tasks/documentation.rake80
-rw-r--r--vendor/rails-2.0.2/railties/lib/tasks/framework.rake118
-rw-r--r--vendor/rails-2.0.2/railties/lib/tasks/log.rake9
-rw-r--r--vendor/rails-2.0.2/railties/lib/tasks/misc.rake10
-rw-r--r--vendor/rails-2.0.2/railties/lib/tasks/rails.rb8
-rw-r--r--vendor/rails-2.0.2/railties/lib/tasks/routes.rake17
-rw-r--r--vendor/rails-2.0.2/railties/lib/tasks/statistics.rake18
-rw-r--r--vendor/rails-2.0.2/railties/lib/tasks/testing.rake118
-rw-r--r--vendor/rails-2.0.2/railties/lib/tasks/tmp.rake37
-rw-r--r--vendor/rails-2.0.2/railties/lib/test_help.rb20
-rw-r--r--vendor/rails-2.0.2/railties/lib/webrick_server.rb165
-rw-r--r--vendor/rails-2.0.2/railties/test/abstract_unit.rb24
-rw-r--r--vendor/rails-2.0.2/railties/test/boot_test.rb179
-rw-r--r--vendor/rails-2.0.2/railties/test/console_app_test.rb29
-rw-r--r--vendor/rails-2.0.2/railties/test/fcgi_dispatcher_test.rb265
-rw-r--r--vendor/rails-2.0.2/railties/test/fixtures/environment_with_constant.rb1
-rw-r--r--vendor/rails-2.0.2/railties/test/fixtures/lib/generators/missing_class/missing_class_generator.rb0
-rw-r--r--vendor/rails-2.0.2/railties/test/fixtures/lib/generators/working/working_generator.rb2
-rw-r--r--vendor/rails-2.0.2/railties/test/fixtures/plugins/default/plugin_with_no_lib_dir/init.rb0
-rw-r--r--vendor/rails-2.0.2/railties/test/fixtures/plugins/default/stubby/init.rb7
-rw-r--r--vendor/rails-2.0.2/railties/test/fixtures/plugins/default/stubby/lib/stubby_mixin.rb2
-rw-r--r--vendor/rails-2.0.2/railties/test/generators/generator_test_helper.rb195
-rw-r--r--vendor/rails-2.0.2/railties/test/generators/rails_model_generator_test.rb109
-rw-r--r--vendor/rails-2.0.2/railties/test/generators/rails_resource_generator_test.rb106
-rw-r--r--vendor/rails-2.0.2/railties/test/generators/rails_scaffold_generator_test.rb185
-rw-r--r--vendor/rails-2.0.2/railties/test/initializer_test.rb218
-rw-r--r--vendor/rails-2.0.2/railties/test/mocks/routes.rb6
-rw-r--r--vendor/rails-2.0.2/railties/test/plugin_loader_test.rb140
-rw-r--r--vendor/rails-2.0.2/railties/test/plugin_locator_test.rb69
-rw-r--r--vendor/rails-2.0.2/railties/test/plugin_test.rb141
-rw-r--r--vendor/rails-2.0.2/railties/test/plugin_test_helper.rb29
-rw-r--r--vendor/rails-2.0.2/railties/test/rails_generator_test.rb137
-rw-r--r--vendor/rails-2.0.2/railties/test/rails_info_controller_test.rb48
-rw-r--r--vendor/rails-2.0.2/railties/test/rails_info_test.rb105
-rw-r--r--vendor/rails-2.0.2/railties/test/secret_key_generation_test.rb35
211 files changed, 20809 insertions, 0 deletions
diff --git a/vendor/rails-2.0.2/railties/CHANGELOG b/vendor/rails-2.0.2/railties/CHANGELOG
new file mode 100644
index 000000000..1dc848bfb
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/CHANGELOG
@@ -0,0 +1,1899 @@
+*2.0.2* (December 16th, 2007)
+
+* Changed the default database from mysql to sqlite3, so now running "rails myapp" will have a config/database.yml that's setup for SQLite3 (which in OS X Leopard is installed by default, so is the gem, so everything Just Works with no database configuration at all). To get a Rails application preconfigured for MySQL, just run "rails -d mysql myapp" [DHH]
+
+* Turned on ActionView::Base.cache_template_loading by default in config/environments/production.rb to prevent file system stat calls for every template loading to see if it changed (this means that you have to restart the application to see template changes in production mode) [DHH]
+
+* Introduce `rake secret` to output a crytographically secure secret key for use with cookie sessions #10363 [revans]
+
+* Fixed that local database creation should consider 127.0.0.1 local #9026 [parcelbrat]
+
+* Fixed that functional tests generated for scaffolds should use fixture calls instead of hard-coded IDs #10435 [boone]
+
+* Added db:migrate:redo and db:migrate:reset for rerunning existing migrations #10431, #10432 [matt]
+
+* RAILS_GEM_VERSION may be double-quoted also. #10443 [James Cox]
+
+* Update rails:freeze:gems to work with RubyGems 0.9.5. [Jeremy Kemper]
+
+
+*2.0.1* (December 7th, 2007)
+
+* Fixed Active Record bug
+
+
+*2.0.0* (December 6th, 2007)
+
+* The test task stops with a warning if you have pending migrations. #10377 [Josh Knowles]
+
+* Add warning to documentation about using transactional fixtures when the code under test uses transactions itself. Closes #7548 [thijsv]
+
+* Update Prototype to 1.6.0.1. [sam]
+
+* Update script.aculo.us to 1.8.0.1. [madrobby]
+
+* Added db:fixtures:identity as a way of locating what ID a foxy fixture was assigned #10332 [jbarnette]
+
+* Generated fixtures should not specify ids since theyre expected to be foxy fixtures #10330 [jbarnette]
+
+* Update to Prototype -r8232. [sam]
+
+* Introduce SecretKeyGenerator for more secure session secrets than CGI::Session's pseudo-random id generator. Consider extracting to Active Support later. #10286 [Hongli Lai]
+
+* RAILS_GEM_VERSION may be set to any valid gem version specifier. #10057 [Chad Woolley, Cheah Chu Yeow]
+
+* Load config/preinitializer.rb, if present, before loading the environment. #9943 [Chad Woolley]
+
+* FastCGI handler ignores unsupported signals like USR2 on Windows. [Grzegorz Derebecki]
+
+* Only load ActionMailer::TestCase if ActionMailer is loaded. Closes #10137 [defunkt]
+
+* Fixed that db:reset would use migrations instead of loading db/schema.rb [DHH]
+
+* Ensure the plugin loader only loads plugins once. Closes #10102 [haruki_zaemon]
+
+* Refactor Plugin Loader. Add plugin lib paths early, and add lots of tests. Closes #9795 [lazyatom]
+
+* Added --skip-timestamps to generators that produce models #10036 [Tim Pope]
+
+* Update Prototype to 1.6.0 and script.aculo.us to 1.8.0. [sam, madrobby]
+
+* Added db:rollback to rollback the schema one version (or multiple as specified by STEP) [Jeffrey Allan Hardy]
+
+* Fix typo in test_helper. Closes #9925 [viktor tron]
+
+* Request profiler. [Jeremy Kemper]
+
+* config/boot.rb correctly detects RAILS_GEM_VERSION. #9834 [alexch, thewoolleyman]
+
+* Fixed incorrect migration number if script/generate executed outside of Rails root #7080 [jeremymcanally]
+
+* Update Prototype to 1.6.0_rc1 and script.aculo.us to 1.8.0 preview 0. [sam, madrobby]
+
+* Generated fixtures use the actual primary key instead of id. #4343 [Frederick Ros, Tarmo Tänav]
+
+* Extend the console +helper+ method to allow you to include custom helpers. e.g:
+ >> helper :posts
+ >> helper.some_method_from_posts_helper(Post.find(1))
+
+* db:create works with remote databases whereas db:create:all only creates
+databases on localhost. #9753 [Trevor Wennblom]
+
+* Removed calls to fixtures in generated tests as fixtures :all is now present by default in test_helper.rb [DHH]
+
+* Add --prefix option to script/server when using mongrel. [dacat]
+
+
+*2.0.0 [Preview Release]* (September 29th, 2007) [Includes duplicates of changes from 1.1.4 - 1.2.3]
+
+* Fixed that installing plugins from SVN repositories that use trunk/ will work #8188 [evan]
+
+* Moved the SourceAnnotationExtractor to a separate file in case libraries try to load the rails rake tasks twice. [Rick]
+
+* Moved Dispatcher to ActionController::Dispatcher. [Jeremy Kemper]
+
+* Changed the default logger from Ruby's own Logger with the clean_logger extensions to ActiveSupport::BufferedLogger for performance reasons [DHH]. (You can change it back with config.logger = Logger.new("/path/to/log", level).)
+
+* Added a default 422.html page to be rendered when ActiveRecord::RecordInvalid, ActiveRecord::RecordNotSaved, or ActionController::InvalidAuthenticityToken is raised [DHH]
+
+* Added --skip-fixture option to script/generate model #6862 [sandofsky]
+
+* Print Rails version when starting console #7440 [eyematz]
+
+* Fixed the placement of fixture files for nested models when generating through script/generate model #7547 [jkit]
+
+* Added TEMPLATE option to rake doc:app to set a custom output template #7737 [Jakob S]
+
+* Added VERBOSE option to rake db:migrate to turn off output #8204 [jbarnette]
+
+* Fixed that rake doc:app should use UTF-8 #8906 [farzy]
+
+* Fixes rake annotations to search erb and builder files as well #9150 [m.langenberg]
+
+* Removed web_service generator [Koz]
+
+* Added the :all option to config.plugins that'll include the rest of the plugins not already explicitly named #9613 [Frederick Cheung]. Example:
+
+ # Loads :classic_pagination before all the other plugins
+ config.plugins = [ :classic_pagination, :all ]
+
+* Added symbols as a legal way of specifying plugins in config.plugins #9629 [tom]
+
+* Removed deprecated task names, like clear_logs, in favor of the new namespaced style [DHH]
+
+* Support multiple config.after_initialize blocks so plugins and apps can more easily cooperate. #9582 [zdennis]
+
+* Added db:drop:all to drop all databases declared in config/database.yml [DHH]
+
+* Use attribute pairs instead of the migration name to create add and remove column migrations. Closes #9166 [Pratik Naik]
+
+ For example:
+
+ ruby script/generation migration AddSomeStuffToCustomers first_name:string last_name:string
+
+ or
+
+ ruby script/generation migration RemoveSomeStuffFromCustomers first_name:string last_name:string
+
+* Add ActiveResource to Rails::Info. Closes #8741 [kampers]
+
+* use Gem.find_name instead of search when freezing gems. Prevent false positives for other gems with rails in the name. Closes #8729 [wselman]
+
+* Automatically generate add/remove column commands in specially named migrations like AddLocationToEvent. Closes #9006 [zenspider]
+
+* Default to plural table name in Rails Generator if ActiveRecord is not present. Closes #8963 [evan]
+
+* Added rake routes for listing all the defined routes in the system. #8795 [Josh Peek]
+
+* db:create creates the database for the current environment if it's on localhost. db:create:all creates local databases for all environments. #8783 [matt]
+
+* Generators: look for generators in all gems, not just those suffixed with _generator, in the gem's generators or rails_generators directory. Allow use of the rails_generators directory instead of the standard generators directory in plugins also. #8730 [Dr Nic, topfunky]
+
+* MySQL, PostgreSQL: database.yml defaults to utf-8. #8701 [matt]
+
+* Added db:version to get the current schema number [via Err The Blog]
+
+* Added --skip-migration option to scaffold and resource generators #8656 [Michael Glaesemann]
+
+* Fix that FCGIs would leave log files open when asked to shut down by USR2. #3028 [Sebastian Kanthak, Josh Peek]
+
+* Fixed that dispatcher preparation callbacks only run once in production mode. Mock Routes.reload so that dispatcher preparation callback tests run. [Rick]
+
+* Fix syntax error in dispatcher than wrecked failsafe responses. #8625 [mtitorenko]
+
+* Scaffolded validation errors set the appropriate HTTP status for XML responses. #6946, #8622 [Manfred Stienstra, mmmultiworks]
+
+* Sexy migrations for the session_migration generator. #8561 [Vladislav]
+
+* Console reload! runs to_prepare callbacks also. #8393 [f.svehla]
+
+* Generated migrations include timestamps by default. #8501 [Shane Vitarana]
+
+* Drop Action Web Service from rails:freeze:edge. [Jeremy Kemper]
+
+* Add db:create, drop, reset, charset, and collation tasks. #8448 [matt]
+
+* Scaffold generator depends on model generator instead of duplicating it. #7222 [bscofield]
+
+* Scaffold generator tests. #8443 [pelle]
+
+* Generated scaffold functional tests use assert_difference. #8421 [Norbert Crombach]
+
+* Update to Prototype 1.5.1. [Sam Stephenson]
+
+* Update to script.aculo.us 1.7.1_beta3. [Thomas Fuchs]
+
+* Generators use *.html.erb view template naming. #8278 [Tim Pope]
+
+* Updated resource_scaffold and model generators to use short-hand style migrations [DHH]
+
+* Updated initializer to only load #{RAILS_ENV}.rb once. Added deprecation warning for config.breakpoint_server. [Nicholas Seckar]
+
+* Removed breakpointer and Binding.of_caller in favor of relying on ruby-debug by Kent Sibilev since the breakpointer has been broken since Ruby 1.8.4 and will not be coming back [DHH]
+
+ To use the new debugger, start your server with script/server --debugger and insert a call to 'debugger'
+ (instead of 'breakpoint') where you want to jump into the debugger.
+
+ BACKWARDS INCOMPATIBILITY NOTE: You must remove the default line 12 from config/environments/development.rb:
+
+ config.breakpoint_server = true
+
+ This configuration option is no longer available. Rails will fail to start in development mode as long as
+ that's still present.
+
+* Resource scaffolding returns the created entity.to_xml. [Jeremy Kemper]
+
+* Resource scaffolding responds to new.xml. #8185 [Eric Mill]
+
+* Include Active Resource in rails:freeze:edge rake task. [Thomas Fuchs]
+
+* Include Active Resource instead of Action Web Service [DHH] You can add AWS back with this in config/environment.rb:
+
+ config.load_paths += %W( #{RAILS_ROOT}/vendor/rails/actionwebservice/lib )
+
+ ...or just gem 'actionwebservice'
+
+* Give generate scaffold a more descriptive database message. Closes #7316 [jeremymcanally]
+
+* Canonicalize RAILS_ROOT by using File.expand_path on Windows, which doesn't have to worry about symlinks, and Pathname#realpath elsewhere, which respects symlinks in relative paths but is incompatible with Windows. #6755 [Jeremy Kemper, trevor]
+
+* Deprecation: remove components from controller paths. [Jeremy Kemper]
+
+* Add environment variable RAILS_DEFAULT_DATABASE, which allows the builtin default of 'mysql' to be overridden. [Nicholas Seckar]
+
+* Windows: include MinGW in RUBY_PLATFORM check. #2982 [okkez000@gmail.com, Kaspar Schiess]
+
+* Split out the basic plugin locator functionality into an abstract super class. Add a FileSystemLocator to do the job of checking the plugin_paths for plugins. Add plugin_locators configuration option which will iterate over the set of plugin locators and load each of the plugin loaders they return. Rename locater everywhere to locator. [Marcel Molina Jr.]
+
+* Split plugin location and loading out of the initializer and into a new Plugin namespace, which includes Plugin::Locater and Plugin::Loader. The loader class that is used can be customized using the config.plugin_loader option. Those monkey patching the plugin loading subsystem take note, the internals changing here will likely break your modifications. The good news is that it should be substantially easier to hook into the plugin locating and loading process now. [Marcel Molina Jr.]
+
+* Added assumption that all plugin creators desire to be sharing individuals and release their work under the MIT license [DHH]
+
+* Added source-annotations extractor tasks to rake [Jamis Buck]. This allows you to add FIXME, OPTIMIZE, and TODO comments to your source code that can then be extracted in concert with rake notes (shows all), rake notes:fixme, rake notes:optimize and rake notes:todo.
+
+* Added fixtures :all to test_helper.rb to assume that most people just want all their fixtures loaded all the time [DHH]
+
+* Added config/initializers where all ruby files within it are automatically loaded after the Rails configuration is done, so you don't have to litter the environment.rb file with a ton of mixed stuff [DHH]
+
+* For new apps, generate a random secret for the cookie-based session store. [Jeremy Kemper]
+
+* Stop swallowing errors during rake test [Koz]
+
+* Update Rails Initializer to use ActionController::Base#view_paths [Rick]
+
+* Fix gem deprecation warnings, which also means depending on RubyGems 0.9.0+ [Chad Fowler]
+
+* Plugins may be symlinked in vendor/plugins. #4245 [brandon, progrium@gmail.com]
+
+* Resource generator depends on the model generator rather than duplicating it. #7269 [bscofield]
+
+* Add/Update usage documentation for script/destroy, resource generator and scaffold_resource generator. Closes #7092, #7271, #7267. [bscofield]
+
+* Update to script.aculo.us 1.7.0. [Thomas Fuchs]
+
+* Update to Prototype 1.5.0. [Sam Stephenson]
+
+* Generator: use destination path for diff tempfiles. #7015 [alfeld]
+
+* Fixed that webrick would strip leading newlines and hang connection #4156 [psross]
+
+* Ensure plugins are in the Dependencies.load_once_paths collection by default. [Rick]
+ If you really want your plugins to reload, add this to the very top of init.rb:
+
+ Dependencies.load_once_paths.delete(lib_path)
+
+* Allow config.to_prepare to work, make the dispatcher safe to 're require'. [Koz, Nicholas Seckar]
+
+* Fix scaffold_resource generator so it respects the --pretend argument when creating the routes file. Closes #6852 [fearoffish]
+
+* Fix Webrick Daemon dispatching bug regarding a bad current working directory. Closes #4899 [Rick Olson]
+
+* Make config.plugins affect the load path and the dependencies system. Allows you to control plugin loading order, and keep disabled plugins off the load path. [James Adam]
+
+* Don't generate a components directory in new Rails apps. [Jeremy Kemper]
+
+* Fixed script/process/spawner to work properly with Mongrel including in -r (daemonize mode) [DHH]
+
+* Added one-letter aliases for the three default environments to script/console, so script/console p will load the production environment (t for test, d for development) [DHH]
+
+* Fixed that script/server running against Mongrel should tail the proper log regardless of the environment [DHH]
+
+* Update initializer to load Rails::VERSION as soon as possible. Closes #6698. [Nicholas Seckar]
+
+* Added ActiveRecord::Base.clear_active_connections! in development mode so the database connection is not carried over from request to request. Some databases won't reread the schema if that doesn't happen (I'm looking at you SQLite), so you have to restart the server after each migration (= no fun) [DHH]
+
+* Made RAILS_GEM_VERSION work for beta gems too, so specifying 1.1.6 will give you 1.1.6.4520 if available [DHH]
+
+* Update to Prototype and script.aculo.us [5579]. [Thomas Fuchs]
+
+* Made script/server work with -e and -d when using Mongrel [DHH]
+
+* Update to Prototype 1.5.0_rc2 [5550] which makes it work in Opera again [Thomas Fuchs]
+
+* Make sure that exceptions which are thrown outside of the user code try their best to be handeled in ApplicationController#rescue_action [Tobias Luetke]
+
+* Rails::VERSION::STRING should always be available without having to require 'rails/version'. #6244 [fearoffish]
+
+* Update to Prototype 1.5.0_rc2. [Sam Stephenson]
+
+* Add grep-based fallback to reaper, to work in pidless setups [Jamis Buck]
+
+* Only wrap request processing with our USR1 signal handler so FastCGI can trap it and raise an exception while waiting for connections. Idle processes exit immediately rather than waiting for another request; active processes gracefully exit when the request is finished. [Jeremy Kemper]
+
+* Alter prior change to use require_dependency instead of require_or_load. Causes ApplicationController to be reloaded again. Closes #6587. [Nicholas Seckar]
+
+* Rake: use absolute paths to load lib and vendor tasks so they may be run outside of RAILS_ROOT. #6584 [jchris]
+
+* Remove temporary crutch to help ApplicationController be unloaded. Closes #6496. [Nicholas Seckar]
+
+* scaffold_resource generator uses _path named routes and head instead of render :nothing => true. #6545 [Josh Susser]
+
+* Generator can show diff on file collision to help you decide whether to skip or overwrite. #6364 [jeffw, Jeremy Kemper]
+
+* Generated directories are recursively svn added, like mkdir -p. #6416 [NeilW]
+
+* resource and scaffold_resource generators add a restful route to config/routes.rb [Jeremy Kemper]
+
+* Revert environment changes for autoload_paths. [Koz]
+
+* Update to latest Prototype, which doesn't serialize disabled form elements, adds clone() to arrays, empty/non-string Element.update() and adds a fixes excessive error reporting in WebKit beta versions [Thomas Fuchs]
+
+* Clean up the output of rake stats, de-emphasise components and apis, and remove the indents for tests [Koz]
+
+* Added option to script/process/spawner of specifying the binding address #5133 [zsombor]
+
+* Update environment.rb comments to include config.autoload_paths. Closes #6478 [caio]
+
+* Update scaffold to use new form_tag block functionality. Closes #6480. [BobSilva]
+
+* Plugin generator: check for class collisions. #4833 [vinbarnes@gmail.com]
+
+* Mailer generator: handle mailers in modules, set mime_version in unit test. [Jeremy Kemper]
+
+* Set $KCODE to 'u' by default to enable the multibyte safe String#chars proxy. [Koz]
+
+* Added config.plugins to control which plugins are loaded #6269 [skaes]. By default, everything in vendor/plugins will be loaded, but if you specify config.plugins, only those will be loaded. Example:
+
+ config.plugins = %w[ routing_navigator simply_helpful ]
+
+* Clean up html on included error pages. [Tim Lucas]
+
+* Fixed default 404.html and 500.htmls to remove extreme ugliness and include human language [DHH]
+
+* Update to latest Prototype and script.aculo.us trunk versions [Thomas Fuchs]
+
+* PostgreSQL: db:test:purge closes open database connections first. #6236 [alex]
+
+* Fixed test:uncommitted on Windows (backslash issue) #4999 [paul@paulbutcher.com]
+
+* Fixed migration creation to work with namespaced models, so script/generate model Gallery::Image will use create_table :gallery_images #6327 [BobSilva]
+
+* Fixed rename_table on SQLite tables with indexes defined #5942 [brandon@opensoul.org]
+
+* Added default timeout setting of 5 seconds to SQLite3 database.yml configurations [DHH]
+
+* Added generated attribute options to script/generate model, like the one found in scaffold_resource and resource [DHH]. Examples:
+
+ ./script/generate model post title:string created_on:date body:text published:boolean
+
+* Added script/generate resource which works just like scaffold_resource, but creates empty placeholders instead of predefined [DHH]
+
+* script/runner can run files, pass on arguments, and be used as a shebang. #6286 [Tuxie, dlpond]
+ #!/usr/bin/env /path/to/my/app/script/runner
+ # Example: just start using your models as if you are in script/console
+ Product.find(:all).each { |product| product.check_inventory }
+
+* Look for rake tasks in plugin subdirs. #6259 [obrie]
+
+* Added map.connect ':controller/:action/:id.:format' as a default route to config/routes.rb [DHH]
+
+* Updated prototype.js to 1.5.0_rc1 with latest fixes. [Rick Olson]
+
+ - XPATH support
+ - Make Form.getElements() return elements in the correct order
+ - fix broken Form.serialize return
+
+* session_migration generator adds an index on updated_at. #6207 [grg]
+
+* script/server creates the tmp/pids directory. #6204 [jonathan]
+
+* Fix script/console --sandbox for internal transactions changes. #5738 [chris@octopod.info, charles.gerungan@gmail.com]
+
+* Remove the uncanny default of adding all app/models/*/ directories to the load path. This change will break application which expect the current behavior. As
+documented in initializer.rb, the workaround is:
+
+ config.autoload_paths += Dir[RAILS_ROOT + '/app/models/*/']
+
+References #6031. [Nicholas Seckar]
+
+* Update to script.aculo.us 1.6.3 [Thomas Fuchs]
+
+* Update to Prototype 1.5.0_rc1 [sam]
+
+* Formally Deprecate the old rake tasks. [Koz]
+
+* Thoroughly test the FCGI dispatcher. #5970 [Kevin Clark]
+
+* Remove Dir.chdir in the Webrick DispatchServlet#initialize method. Fix bad path errors when trying to load config/routes.rb. [Rick Olson]
+
+* Tighten rescue clauses. #5985 [james@grayproductions.net]
+
+* Cleaning up tests. [Kevin Clark, Jeremy Kemper]
+
+* Add Dependencies.load_once_paths. [Nicholas Seckar]
+
+* Updated to script.aculo.us 1.6.2 [Thomas Fuchs]
+
+* Assign Routing.controller_paths; fix script/about and rails info controller. [Nicholas Seckar]
+
+* Don't warn dispatcher of Reloadable deprecations. [Nicholas Seckar]
+
+* Rearrange application resetting and preparation, fix bug with leaking subclasses hash in ActiveRecord::Base [Rick Olson]
+
+ ActiveRecord::Base.reset_subclasses is called before Dependencies are cleared and classes removed.
+ ActiveRecord::Base.instantiate_observers is called during a Dispatcher preparation callback.
+
+* Add missing mock directories from the autoload_paths configuration. [Rick Olson]
+
+* Nested controller scaffolding also nests the generated layout. [iain d broadfoot]
+
+* Add "require 'dispatcher'" to webrick server in the continuing quest to squash webrick weirdness. [Nicholas Seckar]
+
+* Add autoload_paths support to Initializer. [Nicholas Seckar]
+
+* Fix Dispatcher.reset_application! so that AR subclasses are removed and Observers re-initialized *after* Reloadable classes are removed. Closes #5743. [Rick Olson]
+
+* Clarify usage of script/plugin source. Closes #5344. [james.adam@gmail.com]
+
+* Add Dispatcher.to_prepare and config.to_prepare to provide a pre-request hook. [Nicholas Seckar]
+
+* Tweak the Rails load order so observers are loaded after plugins, and reloaded in development mode. Closed #5279. [Rick Olson]
+
+* Added that you can change the web server port in config/lighttpd.conf from script/server --port/-p #5465 [mats@imediatec.co.uk]
+
+* script/performance/profiler compatibility with the new ruby-prof, including an option to choose the results printer. #5679 [shugo@ruby-lang.org]
+
+* Fixed the failsafe response so it uses either the current recognized controller or ApplicationController. [Rick Olson]
+
+* Make sure script/reaper only reaps dispatcher pids by default, and not the spawner's pid. [Jamis Buck]
+
+* Fix script/plugin about so it uses about.yml and not meta.yml. [James Adam]
+
+* Dispatcher processes rescued actions with the same controller that processed the request. #4625 [sd@notso.net]
+
+* rails -d frontbase to create a new project with a frontbase database.yml. #4945 [mlaster@metavillage.com]
+
+* Ensure the logger is initialized. #5629 [mike@clarkware.com]
+
+* Added Mongrel-spawning capabilities to script/process/spawner. Mongrel will be the default choice if installed, otherwise FCGI is tried [DHH]. Examples:
+
+ spawner # starts instances on 8000, 8001, and 8002 using Mongrel if available
+ spawner fcgi # starts instances on 8000, 8001, and 8002 using FCGI
+ spawner mongrel -i 5 # starts instances on 8000, 8001, 8002, 8003, and 8004 using Mongrel
+ spawner -p 9100 -i 10 # starts 10 instances counting from 9100 to 9109 using Mongrel if available
+ spawner -p 9100 -r 5 # starts 3 instances counting from 9100 to 9102 and attempts start them every 5 seconds
+
+ Also note that script/process/reaper is Mongrel capable. So the combination of spawner and reaper is a built-in alternative to something like mongrel_cluster.
+
+* Update scaffolding functional tests to use :id => people(:first) instead of :id => 1. #5612 [evan@protest.net]
+
+* db:test:clone should remove existing tables before reloading the schema. #5607 [sveit@tradeharbor.com]
+
+* Fixed migration generation for class names like ACLController #5197 [brad@madriska.com]
+
+* Added show_source_list and show_call_stack to breakpoints to make it easier to get context #5476 [takiuchi@drecom.co.jp]. Examples:
+
+ irb(#<TopController:0x40822a68>):002:0> show_source_list
+ 0001 class TopController < ApplicationController
+ 0002 def show
+ 0003-> breakpoint
+ 0004 end
+ 0005
+ 0006 def index
+ 0007 end
+ 0008
+ => "/path/to/rails/root/app/controllers/top_controller.rb"
+
+ irb(#<TopController:0x40822a68>):004:0> show_call_stack 3
+ vendor/rails/railties/lib/breakpoint.rb:536:in `breakpoint'
+ vendor/rails/railties/lib/breakpoint.rb:536:in `breakpoint'
+ app/controllers/top_controller.rb:3:in `show'
+ => "/path/to/rails/root/app/controllers/top_controller.rb:3"
+
+* Generate scaffold layout in subdirectory appropriate to its module nesting. #5511 [nils@alumni.rice.edu]
+
+* Mongrel: script/server tails the rails log like it does with lighttpd. Prefer mongrel over lighttpd. #5541 [mike@clarkware.com]
+
+* Don't assume Active Record is available. #5497 [bob@sporkmonger.com]
+
+* Mongrel: script/server works on Win32. #5499 [jeremydurham@gmail.com]
+
+* Remove opts.on { |options[:option_name] } style hash assignment. Closes #4440. [nicksieger@gmail.com]
+
+* Mongrel support for script/server. #5475 [jeremydurham@gmail.com]
+
+* Fix script/plugin so it doesn't barf on invalid URLs [Rick]
+
+* Fix plugin install bug at dir with space. (closes #5359) [Yoshimasa NIWA]
+
+* Fix bug with 'script/plugin install' so it reports unknown plugin names correctly. [Rick]
+
+* Added uninstall.rb hook to plugin handling, such that plugins have a way of removing assets and other artifacts on removal #5003 [takiuchi@drecom.co.jp]
+
+* Create temporary dirs relative to RAILS_ROOT when running script/server #5014 [elliot@townx.org]
+
+* Minor tweak to dispatcher to use recognize instead of recognize!, as per the new routes. [Jamis Buck]
+
+* Make "script/plugin install" work with svn+ssh URLs. [Sam Stephenson]
+
+* Added lib/ to the directories that will get application docs generated [DHH]
+
+* Add observer generator. Closes #5167. [francois.beausoleil@gmail.com]
+
+* Session migration generator obeys pluralize_table_names. #5145 [james.adam@gmail.com]
+
+* rake test:recent understands subdirectories. #2925 [jerrett@bravenet.com]
+
+* The app generator detects the XAMPP package's MySQL socket location. #3832 [elliot@townx.org]
+
+* The app generator sets a session key in application.rb so apps running on the same host may distinguish their cookies. #2967 [rcoder, rails-bug@owl.me.uk]
+
+* Distinguish the spawners for different processes [DHH]
+
+* Added -n/--process to script/process/spawner name the process pid (default is dispatch) [DHH]
+
+* Namespaced OrderedHash so the Rails implementation does not clash with any others. (fixes #4911) [Julian Tarkhanov]
+
+* Replace Ruby's deprecated append_features in favor of included. [Marcel Molina Jr.]
+
+* Added script/process/inspector to do simple process status information on Rails dispatchers keeping pid files in tmp/pids [DHH]
+
+* Added pid file usage to script/process/spawner and script/process/reaper along with a directive in default config/lighttpd.conf file to record the pid. They will all save their pid file in tmp/pids [DHH]
+
+
+*1.2.3* (March 12th, 2007)
+
+* Ruby 1.8.6 compatibility
+
+* Windows: include MinGW in RUBY_PLATFORM check. #2982 [okkez000@gmail.com, Kaspar Schiess]
+
+* Stop swallowing errors during rake test [Koz]
+
+
+*1.2.2* (February 5th, 2007)
+
+* Fix gem deprecation warnings, which also means depending on RubyGems 0.9.0+ [Chad Fowler]
+
+* Require the dispatcher for Rails::Configuration#to_prepare. [Rick]
+
+
+*1.2.1* (January 16th, 2007)
+
+* Updated to Active Record 1.15.1, Action Pack 1.13.1, Action Mailer 1.3.1, Action Web Service 1.2.1
+
+
+*1.2.0* (January 16th, 2007)
+
+* Update to Prototype 1.5.0. [Sam Stephenson]
+
+* Generator: use destination path for diff tempfiles. #7015 [alfeld]
+
+* Fixed that webrick would strip leading newlines and hang connection #4156 [psross]
+
+* Ensure plugins are in the Dependencies.load_once_paths collection by default. [Rick]
+ If you really want your plugins to reload, add this to the very top of init.rb:
+
+ Dependencies.load_once_paths.delete(lib_path)
+
+* Fix scaffold_resource generator so it respects the --pretend argument when creating the routes file. Closes #6852 [fearoffish]
+
+* Fix Webrick Daemon dispatching bug regarding a bad current working directory. Closes #4899 [Rick Olson]
+
+* Make config.plugins affect the load path and the dependencies system. Allows you to control plugin loading order, and keep disabled plugins off the load path. [James Adam]
+
+* Don't generate a components directory in new Rails apps. [Jeremy Kemper]
+
+* Fixed script/process/spawner to work properly with Mongrel including in -r (daemonize mode) [DHH]
+
+* Deprecated the name route "root" as it'll be used as a shortcut for map.connect '' in Rails 2.0 [DHH]
+
+* Fixed that script/server running against Mongrel should tail the proper log regardless of the environment [DHH]
+
+* Update initializer to load Rails::VERSION as soon as possible. Closes #6698. [Nicholas Seckar]
+
+* Added ActiveRecord::Base.clear_active_connections! in development mode so the database connection is not carried over from request to request. Some databases won't reread the schema if that doesn't happen (I'm looking at you SQLite), so you have to restart the server after each migration (= no fun) [DHH]
+
+* Made RAILS_GEM_VERSION work for beta gems too, so specifying 1.1.6 will give you 1.1.6.4520 if available [DHH]
+
+* Update to Prototype and script.aculo.us [5579]. [Sam Stephenson, Thomas Fuchs]
+
+* Made script/server work with -e and -d when using Mongrel [DHH]
+
+* Make sure that exceptions which are thrown outside of the user code try their best to be handeled in ApplicationController#rescue_action [Tobias Luetke]
+
+* Rails::VERSION::STRING should always be available without having to require 'rails/version'. #6244 [fearoffish]
+
+* Add grep-based fallback to reaper, to work in pidless setups [Jamis Buck]
+
+* Only wrap request processing with our USR1 signal handler so FastCGI can trap it and raise an exception while waiting for connections. Idle processes exit immediately rather than waiting for another request; active processes gracefully exit when the request is finished. [Jeremy Kemper]
+
+* Alter prior change to use require_dependency instead of require_or_load. Causes ApplicationController to be reloaded again. Closes #6587. [Nicholas Seckar]
+
+* Rake: use absolute paths to load lib and vendor tasks so they may be run outside of RAILS_ROOT. #6584 [jchris]
+
+* scaffold_resource generator uses _path named routes and head instead of render :nothing => true. #6545 [Josh Susser]
+
+* Generator can show diff on file collision to help you decide whether to skip or overwrite. #6364 [jeffw, Jeremy Kemper]
+
+* Generated directories are recursively svn added, like mkdir -p. #6416 [NeilW]
+
+* resource and scaffold_resource generators add a restful route to config/routes.rb [Jeremy Kemper]
+
+* Revert environment changes for autoload_paths. [Koz]
+
+* Clean up the output of rake stats, de-emphasise components and apis, and remove the indents for tests [Koz]
+
+* Added option to script/process/spawner of specifying the binding address #5133 [zsombor]
+
+* Update environment.rb comments to include config.autoload_paths. Closes #6478 [caio]
+
+* Update scaffold to use new form_tag block functionality. Closes #6480. [BobSilva]
+
+* Plugin generator: check for class collisions. #4833 [vinbarnes@gmail.com]
+
+* Mailer generator: handle mailers in modules, set mime_version in unit test. [Jeremy Kemper]
+
+* Set $KCODE to 'u' by default to enable the multibyte safe String#chars proxy. [Koz]
+
+* Added config.plugins to control which plugins are loaded #6269 [skaes]. By default, everything in vendor/plugins will be loaded, but if you specify config.plugins, only those will be loaded. Example:
+
+ config.plugins = %w[ routing_navigator simply_helpful ]
+
+* Clean up html on included error pages. [Tim Lucas]
+
+* Fixed default 404.html and 500.htmls to remove extreme ugliness and include human language [DHH]
+
+* Update to latest Prototype and script.aculo.us trunk versions [Thomas Fuchs]
+
+* PostgreSQL: db:test:purge closes open database connections first. #6236 [alex]
+
+* Fixed test:uncommitted on Windows (backslash issue) #4999 [paul@paulbutcher.com]
+
+* Fixed migration creation to work with namespaced models, so script/generate model Gallery::Image will use create_table :gallery_images #6327 [BobSilva]
+
+* Fixed rename_table on SQLite tables with indexes defined #5942 [brandon@opensoul.org]
+
+* Added default timeout setting of 5 seconds to SQLite3 database.yml configurations [DHH]
+
+* Added generated attribute options to script/generate model, like the one found in scaffold_resource and resource [DHH]. Examples:
+
+ ./script/generate model post title:string created_on:date body:text published:boolean
+
+* Added script/generate resource which works just like scaffold_resource, but creates empty placeholders instead of predefined [DHH]
+
+* script/runner can run files, pass on arguments, and be used as a shebang. #6286 [Tuxie, dlpond]
+ #!/usr/bin/env /path/to/my/app/script/runner
+ # Example: just start using your models as if you are in script/console
+ Product.find(:all).each { |product| product.check_inventory }
+
+* Look for rake tasks in plugin subdirs. #6259 [obrie]
+
+* Added map.connect ':controller/:action/:id.:format' as a default route to config/routes.rb [DHH]
+
+* session_migration generator adds an index on updated_at. #6207 [grg]
+
+* script/server creates the tmp/pids directory. #6204 [jonathan]
+
+* Fix script/console --sandbox for internal transactions changes. #5738 [chris@octopod.info, charles.gerungan@gmail.com]
+
+* Remove the uncanny default of adding all app/models/*/ directories to the load path. This change will break application which expect the current behavior. As
+documented in initializer.rb, the workaround is:
+
+ config.autoload_paths += Dir[RAILS_ROOT + '/app/models/*/']
+
+References #6031. [Nicholas Seckar]
+
+* Update to script.aculo.us 1.6.3 [Thomas Fuchs]
+
+* Formally Deprecate the old rake tasks. [Koz]
+
+* Thoroughly test the FCGI dispatcher. #5970 [Kevin Clark]
+
+* Remove Dir.chdir in the Webrick DispatchServlet#initialize method. Fix bad path errors when trying to load config/routes.rb. [Rick Olson]
+
+* Tighten rescue clauses. #5985 [james@grayproductions.net]
+
+* Cleaning up tests. [Kevin Clark, Jeremy Kemper]
+
+* Add Dependencies.load_once_paths. [Nicholas Seckar]
+
+* Assign Routing.controller_paths; fix script/about and rails info controller. [Nicholas Seckar]
+
+* Don't warn dispatcher of Reloadable deprecations. [Nicholas Seckar]
+
+* Rearrange application resetting and preparation, fix bug with leaking subclasses hash in ActiveRecord::Base [Rick Olson]
+
+ ActiveRecord::Base.reset_subclasses is called before Dependencies are cleared and classes removed.
+ ActiveRecord::Base.instantiate_observers is called during a Dispatcher preparation callback.
+
+* Add missing mock directories from the autoload_paths configuration. [Rick Olson]
+
+* Nested controller scaffolding also nests the generated layout. [iain d broadfoot]
+
+* Add "require 'dispatcher'" to webrick server in the continuing quest to squash webrick weirdness. [Nicholas Seckar]
+
+* Add autoload_paths support to Initializer. [Nicholas Seckar]
+
+* Fix Dispatcher.reset_application! so that AR subclasses are removed and Observers re-initialized *after* Reloadable classes are removed. Closes #5743. [Rick Olson]
+
+* Clarify usage of script/plugin source. Closes #5344. [james.adam@gmail.com]
+
+* Add Dispatcher.to_prepare and config.to_prepare to provide a pre-request hook. [Nicholas Seckar]
+
+* Tweak the Rails load order so observers are loaded after plugins, and reloaded in development mode. Closed #5279. [Rick Olson]
+
+* Added that you can change the web server port in config/lighttpd.conf from script/server --port/-p #5465 [mats@imediatec.co.uk]
+
+* script/performance/profiler compatibility with the new ruby-prof, including an option to choose the results printer. #5679 [shugo@ruby-lang.org]
+
+* Fixed the failsafe response so it uses either the current recognized controller or ApplicationController. [Rick Olson]
+
+* Make sure script/reaper only reaps dispatcher pids by default, and not the spawner's pid. [Jamis Buck]
+
+* Fix script/plugin about so it uses about.yml and not meta.yml. [James Adam]
+
+* Dispatcher processes rescued actions with the same controller that processed the request. #4625 [sd@notso.net]
+
+* rails -d frontbase to create a new project with a frontbase database.yml. #4945 [mlaster@metavillage.com]
+
+* Ensure the logger is initialized. #5629 [mike@clarkware.com]
+
+* Added Mongrel-spawning capabilities to script/process/spawner. Mongrel will be the default choice if installed, otherwise FCGI is tried [DHH]. Examples:
+
+ spawner # starts instances on 8000, 8001, and 8002 using Mongrel if available
+ spawner fcgi # starts instances on 8000, 8001, and 8002 using FCGI
+ spawner mongrel -i 5 # starts instances on 8000, 8001, 8002, 8003, and 8004 using Mongrel
+ spawner -p 9100 -i 10 # starts 10 instances counting from 9100 to 9109 using Mongrel if available
+ spawner -p 9100 -r 5 # starts 3 instances counting from 9100 to 9102 and attempts start them every 5 seconds
+
+ Also note that script/process/reaper is Mongrel capable. So the combination of spawner and reaper is a built-in alternative to something like mongrel_cluster.
+
+* Update scaffolding functional tests to use :id => people(:first) instead of :id => 1. #5612 [evan@protest.net]
+
+* db:test:clone should remove existing tables before reloading the schema. #5607 [sveit@tradeharbor.com]
+
+* Fixed migration generation for class names like ACLController #5197 [brad@madriska.com]
+
+* Added show_source_list and show_call_stack to breakpoints to make it easier to get context #5476 [takiuchi@drecom.co.jp]. Examples:
+
+ irb(#<TopController:0x40822a68>):002:0> show_source_list
+ 0001 class TopController < ApplicationController
+ 0002 def show
+ 0003-> breakpoint
+ 0004 end
+ 0005
+ 0006 def index
+ 0007 end
+ 0008
+ => "/path/to/rails/root/app/controllers/top_controller.rb"
+
+ irb(#<TopController:0x40822a68>):004:0> show_call_stack 3
+ vendor/rails/railties/lib/breakpoint.rb:536:in `breakpoint'
+ vendor/rails/railties/lib/breakpoint.rb:536:in `breakpoint'
+ app/controllers/top_controller.rb:3:in `show'
+ => "/path/to/rails/root/app/controllers/top_controller.rb:3"
+
+* Generate scaffold layout in subdirectory appropriate to its module nesting. #5511 [nils@alumni.rice.edu]
+
+* Mongrel: script/server tails the rails log like it does with lighttpd. Prefer mongrel over lighttpd. #5541 [mike@clarkware.com]
+
+* Don't assume Active Record is available. #5497 [bob@sporkmonger.com]
+
+* Mongrel: script/server works on Win32. #5499 [jeremydurham@gmail.com]
+
+* Remove opts.on { |options[:option_name] } style hash assignment. Closes #4440. [nicksieger@gmail.com]
+
+* Mongrel support for script/server. #5475 [jeremydurham@gmail.com]
+
+* Fix script/plugin so it doesn't barf on invalid URLs [Rick]
+
+* Fix plugin install bug at dir with space. (closes #5359) [Yoshimasa NIWA]
+
+* Fix bug with 'script/plugin install' so it reports unknown plugin names correctly. [Rick]
+
+* Added uninstall.rb hook to plugin handling, such that plugins have a way of removing assets and other artifacts on removal #5003 [takiuchi@drecom.co.jp]
+
+* Create temporary dirs relative to RAILS_ROOT when running script/server #5014 [elliot@townx.org]
+
+* Minor tweak to dispatcher to use recognize instead of recognize!, as per the new routes. [Jamis Buck]
+
+* Make "script/plugin install" work with svn+ssh URLs. [Sam Stephenson]
+
+* Added lib/ to the directories that will get application docs generated [DHH]
+
+* Add observer generator. Closes #5167. [francois.beausoleil@gmail.com]
+
+* Session migration generator obeys pluralize_table_names. #5145 [james.adam@gmail.com]
+
+* rake test:recent understands subdirectories. #2925 [jerrett@bravenet.com]
+
+* The app generator detects the XAMPP package's MySQL socket location. #3832 [elliot@townx.org]
+
+* The app generator sets a session key in application.rb so apps running on the same host may distinguish their cookies. #2967 [rcoder, rails-bug@owl.me.uk]
+
+* Distinguish the spawners for different processes [DHH]
+
+* Added -n/--process to script/process/spawner name the process pid (default is dispatch) [DHH]
+
+* Namespaced OrderedHash so the Rails implementation does not clash with any others. (fixes #4911) [Julian Tarkhanov]
+
+* Replace Ruby's deprecated append_features in favor of included. [Marcel Molina Jr.]
+
+* Added script/process/inspector to do simple process status information on Rails dispatchers keeping pid files in tmp/pids [DHH]
+
+* Added pid file usage to script/process/spawner and script/process/reaper along with a directive in default config/lighttpd.conf file to record the pid. They will all save their pid file in tmp/pids [DHH]
+
+
+*1.1.6* (August 10th, 2006)
+
+* Additional security patch
+
+
+*1.1.5* (August 8th, 2006)
+
+* Mention in docs that config.frameworks doesn't work when getting Rails via Gems. #4857 [Alisdair McDiarmid]
+
+* Change the scaffolding layout to use yield rather than @content_for_layout. [Marcel Molina Jr.]
+
+* Includes critical security patch
+
+
+*1.1.4* (June 29th, 2006)
+
+* Remove use of opts.on { |options[:name] } style hash assignment. References #4440. [headius@headius.com]
+
+* Updated to Action Pack 1.12.3, ActionWebService 1.1.4, ActionMailer 1.2.3
+
+
+*1.1.3* (June 27th, 2006)
+
+* Updated to Active Record 1.14.3, Action Pack 1.12.2, ActionWebService 1.1.3, ActionMailer 1.2.2
+
+
+*1.1.2* (April 9th, 2006)
+
+* Mention in docs that config.frameworks doesn't work when getting Rails via Gems. Closes #4857. [Alisdair McDiarmid]
+
+* Change the scaffolding layout to use yield rather than @content_for_layout. [Marcel Molina Jr.]
+
+* Added rake rails:update:configs to update config/boot.rb from the latest (also included in rake rails:update) [DHH]
+
+* Fixed that boot.rb would set RAILS_GEM_VERSION twice, not respect an uncommented RAILS_GEM_VERSION line, and not use require_gem [DHH]
+
+
+*1.1.1* (April 6th, 2006)
+
+* Enhances plugin#discover allowing it to discover svn:// like URIs (closes #4565) [ruben.nine@gmail.com]
+
+* Update to Prototype 1.5.0_rc0 [Sam Stephenson]
+
+* Fixed that the -r/--ruby path option of the rails command was not being respected #4549 [ryan.raaum@gmail.com]
+
+* Added that Dispatcher exceptions should not be shown to the user unless a default log has not been configured. Instead show public/500.html [DHH]
+
+* Fixed that rake clone_structure_to_test should quit on pgsql if the dump is unsuccesful #4585 [augustz@augustz.com]
+
+* Fixed that rails --version should have the return code of 0 (success) #4560 [blair@orcaware.com]
+
+* Install alias so Rails::InfoController is accessible at /rails_info. Closes #4546. [Nicholas Seckar]
+
+* Fixed that spawner should daemonize if running in repeat mode [DHH]
+
+* Added TAG option for rake rails:freeze:edge, so you can say rake rails:freeze:edge TAG=rel_1-1-0 to lock to the 1.1.0 release [DHH]
+
+* Applied Prototype $() performance patches (#4465, #4477) and updated script.aculo.us [Sam Stephenson, Thomas Fuchs]
+
+* Use --simple-prompt instead of --prompt-mode simple for console compatibility with Windows/Ruby 1.8.2 #4532 [starr@starrnhorne.com]
+
+* Make Rails::VERSION implicitly loadable #4491. [Nicholas Seckar]
+
+* Fixed rake rails:freeze:gems #4518 [benji@silverinsanity.com]
+
+* Added -f/--freeze option to rails command for freezing the application to the Rails version it was generated with [DHH]
+
+* Added gem binding of apps generated through the rails command to the gems of they were generated with [Nicholas Seckar]
+
+* Added expiration settings for JavaScript, CSS, HTML, and images to default lighttpd.conf [DHH]
+
+* Added gzip compression for JavaScript, CSS, and HTML to default lighttpd.conf [DHH]
+
+* Avoid passing escapeHTML non-string in Rails' info controller [Nicholas Seckar]
+
+
+*1.1.0* (March 27th, 2006)
+
+* Allow db:fixtures:load to load a subset of the applications fixtures. [Chad Fowler]
+
+ ex.
+
+ rake db:fixtures:load FIXTURES=customers,plans
+
+* Update to Prototype 1.5.0_pre1 [Sam Stephenson]
+
+* Update to script.aculo.us 1.6 [Thomas Fuchs]
+
+* Add an integration_test generator [Jamis Buck]
+
+* Make all ActionView helpers available in the console from the helper method for debugging purposes. n.b.: Only an 80% solution. Some stuff won't work, most will. [Marcel Molina Jr.]
+
+ ex.
+
+ >> puts helper.options_for_select([%w(a 1), %w(b 2), %w(c 3)])
+ <option value="1">a</option>
+ <option value="2">b</option>
+ <option value="3">c</option>
+ => nil
+
+* Replaced old session rake tasks with db:sessions:create to generate a migration, and db:sessions:clear to remove sessions. [Rick Olson]
+
+* Reject Ruby 1.8.3 when loading Rails; extract version checking code. [Chad Fowler]
+
+* Remove explicit loading of RailsInfo and RailsInfoController. [Nicholas Seckar]
+
+* Move RailsInfo and RailsInfoController to Rails::Info and Rails::InfoController. [Nicholas Seckar]
+
+* Extend load path with Railties' builtin directory to make adding support code easy. [Nicholas Seckar]
+
+* Fix the rails_info controller by explicitly loading it, and marking it as not reloadable. [Nicholas Seckar]
+
+* Fixed rails:freeze:gems for Windows #3274 [paul@paulbutcher.com]
+
+* Added 'port open?' check to the spawner when running in repeat mode so we don't needlessly boot the dispatcher if the port is already in use anyway #4089 [guy.naor@famundo.com]
+
+* Add verification to generated scaffolds, don't allow get for unsafe actions [Michael Koziarski]
+
+* Don't replace application.js in public/javascripts if it already exists [Cody Fauser]
+
+* Change test:uncommitted to delay execution of `svn status` by using internal Rake API's. [Nicholas Seckar]
+
+* Use require_library_or_gem to load rake in commands/server.rb. Closes #4205. [rob.rasmussen@gmail.com]
+
+* Use the Rake API instead of shelling out to create the tmp directory in commands/server.rb. [Chad Fowler]
+
+* Added a backtrace to the evil WSOD (White Screen of Death). Closes #4073. TODO: Clearer exceptions [Rick Olson]
+
+* Added tracking of database and framework versions in script/about #4088 [charles.gerungan@gmail.com/Rick Olson]
+
+* Added public/javascripts/application.js as a sample since it'll automatically be included in javascript_include_tag :defaults [DHH]
+
+* Added socket cleanup for lighttpd, both before and after [DHH]
+
+* Added automatic creation of tmp/ when running script/server [DHH]
+
+* Added silence_stream that'll work on both STDERR or STDOUT or any other stream and deprecated silence_stderr in the process [DHH]
+
+* Added reload! method to script/console to reload all models and others that include Reloadable without quitting the console #4056 [esad@esse.at]
+
+* Added that rake rails:freeze:edge will now just export all the contents of the frameworks instead of just lib, so stuff like rails:update:scripts, rails:update:javascripts, and script/server on lighttpd still just works #4047 [DHH]
+
+* Added fix for upload problems with lighttpd from Safari/IE to config/lighttpd.conf #3999 [thijs@fngtps.com]
+
+* Added test:uncommitted to test changes since last checkin to Subversion #4035 [technomancy@gmail.com]
+
+* Help script/about print the correct svn revision when in a non-English locale. #4026 [babie7a0@ybb.ne.jp]
+
+* Add 'app' accessor to script/console as an instance of Integration::Session [Jamis Buck]
+
+* Generator::Base#usage takes an optional message argument which defaults to Generator::Base#usage_message. [Jeremy Kemper]
+
+* Remove the extraneous AR::Base.threaded_connections setting from the webrick server. [Jeremy Kemper]
+
+* Add integration test support to app generation and testing [Jamis Buck]
+
+* Added namespaces to all tasks, so for example load_fixtures is now db:fixtures:load. All the old task names are still valid, they just point to the new namespaced names. "rake -T" will only show the namespaced ones, though [DHH]
+
+* CHANGED DEFAULT: ActiveRecord::Base.schema_format is now :ruby by default instead of :sql. This means that we'll assume you want to live in the world of db/schema.rb where the grass is green and the girls are pretty. If your schema contains un-dumpable elements, such as constraints or database-specific column types, you just got an invitation to either 1) patch the dumper to include foreign key support, 2) stop being db specific, or 3) just change the default in config/environment.rb to config.active_record.schema_format = :sql -- we even include an example for that on new Rails skeletons now. Brought to you by the federation of opinionated framework builders! [DHH]
+
+* Added -r/--repeat option to script/process/spawner that offers the same loop protection as the spinner did. This deprecates the script/process/spinner, so it's no longer included in the default Rails skeleton, but still available for backwards compatibility #3461 [ror@andreas-s.net]
+
+* Added collision option to template generation in generators #3329 [anna@wota.jp]. Examples:
+
+ m.template "stuff.config" , "config/stuff.config" , :collision => :skip
+ m.template "auto-stamping", "config/generator.log", :collision => :force
+
+* Added more information to script/plugin's doings to ease debugging #3755 [Rick Olson]
+
+* Changed the default configuration for lighttpd to use tmp/sockets instead of log/ for the FastCGI sockets [DHH]
+
+* Added a default configuration of the FileStore for fragment caching if tmp/cache is available, which makes action/fragment caching ready to use out of the box with no additional configuration [DHH]
+
+* Changed the default session configuration to place sessions in tmp/sessions, if that directory is available, instead of /tmp (this essentially means a goodbye to 9/10 White Screen of Death errors and should have web hosting firms around the world cheering) [DHH]
+
+* Added tmp/sessions, tmp/cache, and tmp/sockets as default directories in the Rails skeleton [DHH]
+
+* Added that script/generate model will now automatically create a migration file for the model created. This can be turned off by calling the generator with --skip-migration [DHH]
+
+* Added -d/--database option to the rails command, so you can do "rails --database=sqlite2 myapp" to start a new application preconfigured to use SQLite2 as the database. Removed the configuration examples from SQLite and PostgreSQL from the default MySQL configuration [DHH]
+
+* Allow script/server -c /path/to/lighttpd.conf [Jeremy Kemper]
+
+* Remove hardcoded path to reaper script in script/server [Jeremy Kemper]
+
+* Update script.aculo.us to V1.5.3 [Thomas Fuchs]
+
+* Added SIGTRAP signal handler to RailsFCGIHandler that'll force the process into a breakpoint after the next request. This breakpoint can then be caught with script/breakpointer and give you access to the Ruby image inside that process. Useful for debugging memory leaks among other things [DHH]
+
+* Changed default lighttpd.conf to use CWD from lighttpd 1.4.10 that allows the same configuration to be used for both detach and not. Also ensured that auto-repeaping of FCGIs only happens when lighttpd is not detached. [DHH]
+
+* Added Configuration#after_initialize for registering a block which gets called after the framework is fully initialized. Useful for things like per-environment configuration of plugins. [Michael Koziarski]
+
+* Added check for RAILS_FRAMEWORK_ROOT constant that allows the Rails framework to be found in a different place than vendor/rails. Should be set in boot.rb. [DHH]
+
+* Fixed that static requests could unlock the mutex guarding dynamic requests in the WEBrick servlet #3433 [tom@craz8.com]
+
+* Fixed documentation tasks to work with Rake 0.7.0 #3563 [kazuhiko@fdiary.net]
+
+* Update to Prototype 1.5.0_pre0 [Sam Stephenson]
+
+* Sort the list of plugins so we load in a consistent order [Rick Olson]
+
+* Show usage when script/plugin is called without arguments [tom@craz8.com]
+
+* Corrected problems with plugin loader where plugins set 'name' incorrectly #3297 [anna@wota.jp]
+
+* Make migration generator only report on exact duplicate names, not partial dupliate names. #3442 [jeremy@planetargon.com Marcel Molina Jr.]
+
+* Fix typo in mailer generator USAGE. #3458 [chriztian.steinmeier@gmail.com]
+
+* Ignore version mismatch between pg_dump and the database server. #3457 [simon.stapleton@gmail.com]
+
+* Reap FCGI processes after lighttpd exits. [Sam Stephenson]
+
+* Honor ActiveRecord::Base.pluralize_table_names when creating and destroying session store table. #3204. [rails@bencurtis.com, Marcel Molina Jr.]
+
+*1.0.0* (December 13th, 2005)
+
+* Update instructions on how to find and install generators. #3172. [Chad Fowler]
+
+* Generator looks in vendor/generators also. [Chad Fowler]
+
+* Generator copies files in binary mode. #3156 [minimudboy@gmail.com]
+
+* Add builtin/ to the gemspec. Closes #3047. [Nicholas Seckar, Sam Stephenson]
+
+* Add install.rb file to plugin generation which is loaded, if it exists, when you install a plugin. [Marcel Molina Jr.]
+
+* Run initialize_logger in script/lighttpd to ensure the log file exists before tailing it. [Sam Stephenson]
+
+* Make load_fixtures include csv fixtures. #3053. [me@mdaines.com]
+
+* Fix freeze_gems so that the latest rails version is dumped by default. [Nicholas Seckar]
+
+* script/plugin: handle root paths and plugin names which contain spaces. #2995 [justin@aspect.net]
+
+* Model generator: correct relative path to test_helper in unit test. [Jeremy Kemper]
+
+* Make the db_schema_dump task honor the SCHEMA environment variable if present the way db_schema_import does. #2931. [Blair Zajac]
+
+* Have the lighttpd server script report the actual ip to which the server is bound. #2903. [Adam]
+
+* Add plugin library directories to the load path after the lib directory so that libraries in the lib directory get precedence. #2910. [james.adam@gmail.com]
+
+* Make help for the console command more explicit about how to specify the desired environment in which to run the console. #2911. [anonymous]
+
+* PostgreSQL: the purge_test_database Rake task shouldn't explicitly specify the template0 template when creating a fresh test database. #2964 [dreamer3@gmail.com]
+
+* Introducing the session_migration generator. Creates an add_session_table migration. Allows generator to specify migrations directory. #2958, #2960 [Rick Olson]
+
+* script/console uses RAILS_ENV environment variable if present. #2932 [Blair Zajac <blair@orcaware.com>
+
+* Windows: eliminate the socket option in database.yml. #2924 [Wayne Vucenic <waynev@gmail.com>]
+
+* Eliminate nil from newly generated logfiles. #2927 [Blair Zajac <blair@orcaware.com>]
+
+* Rename Version constant to VERSION. #2802 [Marcel Molina Jr.]
+
+* Eliminate Subversion dependencies in scripts/plugin. Correct install options. Introduce --force option to reinstall a plugin. Remove useless --long option for list. Use --quiet to quiet the download output and --revision to update to a specific svn revision. #2842 [Chad Fowler, Rick Olson]
+
+* SQLite: the clone_structure_to_test and purge_test_database Rake tasks should always use the test environment. #2846 [Rick Olson]
+
+* Make sure that legacy db tasks also reference :database for SQLite #2830 [kazuhiko@fdiary.net]
+
+* Pass __FILE__ when evaluating plugins' init.rb. #2817 [james.adam@gmail.com]
+
+* Better svn status matching for generators. #2814 [François Beausoleil <francois.beausoleil@gmail.com>, Blair Zajac <blair@orcaware.com>]
+
+* Don't reload routes until plugins have been loaded so they have a chance to extend the routing capabilities [DHH]
+
+* Don't detach or fork for script/server tailing [Nicholas Seckar]
+
+* Changed all script/* to use #!/usr/bin/env ruby instead of hard-coded Ruby path. public/dispatcher.* still uses the hard-coded path for compatibility with web servers that don't have Ruby in path [DHH]
+
+* Force RAILS_ENV to be "test" when running tests, so that ENV["RAILS_ENV"] = "production" in config/environment.rb doesn't wreck havok [DHH] #2660
+
+* Correct versioning in :freeze_gems Rake task. #2778 [jakob@mentalized.net, Jeremy Kemper]
+
+* Added an omnipresent RailsInfoController with a properties action that delivers an HTML rendering of Rails::Info (but only when local_request? is true). Added a new default index.html which fetches this with Ajax. [Sam Stephenson]
+
+
+*0.14.3 (RC4)* (November 7th, 2005)
+
+* Add 'add_new_scripts' rake task for adding new rails scripts to script/* [Jamis Buck]
+
+* Remove bogus hyphen from script/process/reaper calls to 'ps'. #2767 [anonymous]
+
+* Copy lighttpd.conf when it is first needed, instead of on app creation [Jamis Buck]
+
+* Use require_library_or_gem 'fcgi' in script/server [Sam Stephenson]
+
+* Added default lighttpd config in config/lighttpd.conf and added a default runner for lighttpd in script/server (works like script/server, but using lighttpd and FastCGI). It will use lighttpd if available, otherwise WEBrick. You can force either or using 'script/server lighttpd' or 'script/server webrick' [DHH]
+
+* New configuration option config.plugin_paths which may be a single path like the default 'vendor/plugins' or an array of paths: ['vendor/plugins', 'lib/plugins']. [Jeremy Kemper]
+
+* Plugins are discovered in nested paths, so you can organize your plugins directory as you like. [Jeremy Kemper]
+
+* Refactor load_plugin from load_plugins. #2757 [alex.r.moon@gmail.com]
+
+* Make use of silence_stderr in script/lighttpd, script/plugin, and Rails::Info [Sam Stephenson]
+
+* Enable HTTP installation of plugins when svn isn't avaialable. Closes #2661. [Chad Fowler]
+
+* Added script/about to display formatted Rails::Info output [Sam Stephenson]
+
+* Added Rails::Info to catalog assorted information about a Rails application's environment [Sam Stephenson]
+
+* Tail the logfile when running script/server lighttpd in the foreground [Sam Stephenson]
+
+* Try to guess the port number from config/lighttpd.conf in script/server lighttpd [Sam Stephenson]
+
+* Don't reap spawn-fcgi. #2727 [matthew@walker.wattle.id.au]
+
+* Reaper knows how to find processes even if the dispatch path is very long. #2711 [matthew@walker.wattle.id.au]
+
+* Make fcgi handler respond to TERM signals with an explicit exit [Jamis Buck]
+
+* Added demonstration of fixture use to the test case generated by the model generator [DHH]
+
+* If specified, pass PostgreSQL client character encoding to createdb. #2703 [Kazuhiko <kazuhiko@fdiary.net>]
+
+* Catch CGI multipart parse errors. Wrap dispatcher internals in a failsafe response handler. [Jeremy Kemper]
+
+* The freeze_gems Rake task accepts the VERSION environment variable to decide which version of Rails to pull into vendor/rails. [Chad Fowler, Jeremy Kemper]
+
+* Removed script.aculo.us.js, builder.js and slider.js (preperation for move of scriptaculous extensions to plugins, core scriptaculous will remain in Railties) [Thomas Fuchs]
+
+* The freeze_edge Rake task does smarter svn detection and can export a specific revision by passing the REVISION environment variable. For example: rake freeze_edge REVISION=1234. #2663 [Rick Olson]
+
+* Comment database.yml and include PostgreSQL and SQLite examples. [Jeremy Kemper]
+
+* Improve script/plugin on Windows. #2646 [Chad Fowler]
+
+* The *_plugindoc Rake tasks look deeper into the plugins' lib directories. #2652 [bellis@deepthought.org]
+
+* The PostgreSQL :db_structure_dump Rake task limits its dump to the schema search path in database.yml. [Anatol Pomozov <anatol.pomozov@gmail.com>]
+
+* Add task to generate rdoc for all installed plugins. [Marcel Molina]
+
+* Update script.aculo.us to V1.5_rc4 [Thomas Fuchs]
+
+* Add default Mac + DarwinPorts MySQL socket locations to the app generator. [Jeremy Kemper]
+
+* Migrations may be destroyed: script/destroy migration foo. #2635 [Charles M. Gerungan <charles.gerungan@gmail.com>, Jamis Buck, Jeremy Kemper]
+
+* Added that plugins can carry generators and that generator stub files can be created along with new plugins using script/generate plugin <name> --with-generator [DHH]
+
+* Removed app/apis as a default empty dir since its automatically created when using script/generate web_service [DHH]
+
+* Added script/plugin to manage plugins (install, remove, list, etc) [Ryan Tomayko]
+
+* Added test_plugins task: Run the plugin tests in vendor/plugins/**/test (or specify with PLUGIN=name) [DHH]
+
+* Added plugin generator to create a stub structure for a new plugin in vendor/plugins (see "script/generate plugin" for help) [DHH]
+
+* Fixed scaffold generator when started with only 1 parameter #2609 [self@mattmower.com]
+
+* rake should run functional tests even if the unit tests have failures [Jim Weirich]
+
+* Back off cleanpath to be symlink friendly. Closes #2533 [Nicholas Seckar]
+
+* Load rake task files in alphabetical order so you can build dependencies and count on them #2554 [Blair Zajac]
+
+
+*0.14.2 (RC3)* (October 26th, 2005)
+
+* Constants set in the development/test/production environment file are set in Object
+
+* Scaffold generator pays attention to the controller name. #2562 [self@mattmower.com]
+
+* Include tasks from vendor/plugins/*/tasks in the Rakefile #2545 [Rick Olson]
+
+
+*0.14.1 (RC2)* (October 19th, 2005)
+
+* Don't clean RAILS_ROOT on windows
+
+* Remove trailing '/' from RAILS_ROOT [Nicholas Seckar]
+
+* Upgraded to Active Record 1.12.1 and Action Pack 1.10.1
+
+
+*0.14.0 (RC1)* (October 16th, 2005)
+
+* Moved generator folder from RAILS_ROOT/generators to RAILS_ROOT/lib/generators [Tobias Luetke]
+
+* Fix rake dev and related commands [Nicholas Seckar]
+
+* The rails command tries to deduce your MySQL socket by running `mysql_config
+--socket`. If it fails, default to /path/to/your/mysql.sock
+
+* Made the rails command use the application name for database names in the tailored database.yml file. Example: "rails ~/projects/blog" will use "blog_development" instead of "rails_development". [Florian Weber]
+
+* Added Rails framework freezing tasks: freeze_gems (freeze to current gems), freeze_edge (freeze to Rails SVN trunk), unfreeze_rails (float with newest gems on system)
+
+* Added update_javascripts task which will fetch all the latest js files from your current rails install. Use after updating rails. [Tobias Luetke]
+
+* Added cleaning of RAILS_ROOT to useless elements such as '../non-dot-dot/'. Provides cleaner backtraces and error messages. [Nicholas Seckar]
+
+* Made the instantiated/transactional fixtures settings be controlled through Rails::Initializer. Transactional and non-instantiated fixtures are default from now on. [Florian Weber]
+
+* Support using different database adapters for development and test with ActiveRecord::Base.schema_format = :ruby [Sam Stephenson]
+
+* Make webrick work with session(:off)
+
+* Add --version, -v option to the Rails command. Closes #1840. [stancell]
+
+* Update Prototype to V1.4.0_pre11, script.aculo.us to V1.5_rc3 [2504] and fix the rails generator to include the new .js files [Thomas Fuchs]
+
+* Make the generator skip a file if it already exists and is identical to the new file.
+
+* Add experimental plugin support #2335
+
+* Made Rakefile aware of new .js files in script.aculo.us [Thomas Fuchs]
+
+* Make table_name and controller_name in generators honor AR::Base.pluralize_table_names. #1216 #2213 [kazuhiko@fdiary.net]
+
+* Clearly label functional and unit tests in rake stats output. #2297 [lasse.koskela@gmail.com]
+
+* Make the migration generator only check files ending in *.rb when calculating the next file name #2317 [Chad Fowler]
+
+* Added prevention of duplicate migrations from the generator #2240 [fbeausoleil@ftml.net]
+
+* Add db_schema_dump and db_schema_import rake tasks to work with the new ActiveRecord::SchemaDumper (for dumping a schema to and reading a schema from a ruby file).
+
+* Reformed all the config/environments/* files to conform to the new Rails::Configuration approach. Fully backwards compatible.
+
+* Added create_sessions_table, drop_sessions_table, and purge_sessions_table as rake tasks for databases that supports migrations (MySQL, PostgreSQL, SQLite) to get a table for use with CGI::Session::ActiveRecordStore
+
+* Added dump of schema version to the db_structure_dump task for databases that support migrations #1835 [Rick Olson]
+
+* Fixed script/profiler for Ruby 1.8.2 #1863 [Rick Olson]
+
+* Fixed clone_structure_to_test task for SQLite #1864 [jon@burningbush.us]
+
+* Added -m/--mime-types option to the WEBrick server, so you can specify a Apache-style mime.types file to load #2059 [ask@develooper.com]
+
+* Added -c/--svn option to the generator that'll add new files and remove destroyed files using svn add/revert/remove as appropriate #2064 [kevin.clark@gmail.com]
+
+* Added -c/--charset option to WEBrick server, so you can specify a default charset (which without changes is UTF-8) #2084 [wejn@box.cz]
+
+* Make the default stats task extendable by modifying the STATS_DIRECTORIES constant
+
+* Allow the selected environment to define RAILS_DEFAULT_LOGGER, and have Rails::Initializer use it if it exists.
+
+* Moved all the shared tasks from Rakefile into Rails, so that the Rakefile is empty and doesn't require updating.
+
+* Added Rails::Initializer and Rails::Configuration to abstract all of the common setup out of config/environment.rb (uses config/boot.rb to bootstrap the initializer and paths)
+
+* Fixed the scaffold generator to fail right away if the database isn't accessible instead of in mid-air #1169 [Chad Fowler]
+
+* Corrected project-local generator location in scripts.rb #2010 [Michael Schuerig]
+
+* Don't require the environment just to clear the logs #2093 [Scott Barron]
+
+* Make the default rakefile read *.rake files from config/tasks (for easy extension of the rakefile by e.g. generators)
+
+* Only load breakpoint in development mode and when BREAKPOINT_SERVER_PORT is defined.
+
+* Allow the --toggle-spin switch on process/reaper to be negated
+
+* Replace render_partial with render :partial in scaffold generator [Nicholas Seckar]
+
+* Added -w flag to ps in process/reaper #1934 [Scott Barron]
+
+* Allow ERb in the database.yml file (just like with fixtures), so you can pull out the database configuration in environment variables #1822 [Duane Johnson]
+
+* Added convenience controls for FCGI processes (especially when managed remotely): spinner, spawner, and reaper. They reside in script/process. More details can be had by calling them with -h/--help.
+
+* Added load_fixtures task to the Rakefile, which will load all the fixtures into the database for the current environment #1791 [Marcel Molina]
+
+* Added an empty robots.txt to public/, so that web servers asking for it won't trigger a dynamic call, like favicon.ico #1738 [michael@schubert]
+
+* Dropped the 'immediate close-down' of FCGI processes since it didn't work consistently and produced bad responses when it didn't. So now a TERM ensures exit after the next request (just as if the process is handling a request when it receives the signal). This means that you'll have to 'nudge' all FCGI processes with a request in order to ensure that they have all reloaded. This can be done by something like ./script/process/repear --nudge 'http://www.myapp.com' --instances 10, which will load the myapp site 10 times (and thus hit all of the 10 FCGI processes once, enough to shut down).
+
+
+*0.13.1* (11 July, 2005)
+
+* Look for app-specific generators in RAILS_ROOT/generators rather than the clunky old RAILS_ROOT/script/generators. Nobody really uses this feature except for the unit tests, so it's a negligible-impact change. If you want to work with third-party generators, drop them in ~/.rails/generators or simply install gems.
+
+* Fixed that each request with the WEBrick adapter would open a new database connection #1685 [Sam Stephenson]
+
+* Added support for SQL Server in the database rake tasks #1652 [ken.barker@gmail.com] Note: osql and scptxfr may need to be installed on your development environment. This involves getting the .exes and a .rll (scptxfr) from a production SQL Server (not developer level SQL Server). Add their location to your Environment PATH and you are all set.
+
+* Added a VERSION parameter to the migrate task that allows you to do "rake migrate VERSION=34" to migrate to the 34th version traveling up or down depending on the current version
+
+* Extend Ruby version check to include RUBY_RELEASE_DATE >= '2005-12-25', the final Ruby 1.8.2 release #1674 [court3nay@gmail.com]
+
+* Improved documentation for environment config files #1625 [court3nay@gmail.com]
+
+
+*0.13.0* (6 July, 2005)
+
+* Changed the default logging level in config/environment.rb to INFO for production (so SQL statements won't be logged)
+
+* Added migration generator: ./script/generate migration add_system_settings
+
+* Added "migrate" as rake task to execute all the pending migrations from db/migrate
+
+* Fixed that model generator would make fixtures plural, even if ActiveRecord::Base.pluralize_table_names was false #1185 [Marcel Molina]
+
+* Added a DOCTYPE of HTML transitional to the HTML files generated by Rails #1124 [Michael Koziarski]
+
+* SIGTERM also gracefully exits dispatch.fcgi. Ignore SIGUSR1 on Windows.
+
+* Add the option to manually manage garbage collection in the FastCGI dispatcher. Set the number of requests between GC runs in your public/dispatch.fcgi [skaes@web.de]
+
+* Allow dynamic application reloading for dispatch.fcgi processes by sending a SIGHUP. If the process is currently handling a request, the request will be allowed to complete first. This allows production fcgi's to be reloaded without having to restart them.
+
+* RailsFCGIHandler (dispatch.fcgi) no longer tries to explicitly flush $stdout (CgiProcess#out always calls flush)
+
+* Fixed rakefile actions against PostgreSQL when the password is all numeric #1462 [michael@schubert.cx]
+
+* ActionMailer::Base subclasses are reloaded with the other rails components #1262
+
+* Made the WEBrick adapter not use a mutex around action performance if ActionController::Base.allow_concurrency is true (default is false)
+
+* Fixed that mailer generator generated fixtures/plural while units expected fixtures/singular #1457 [Scott Barron]
+
+* Added a 'whiny nil' that's aim to ensure that when users pass nil to methods where that isn't appropriate, instead of NoMethodError? and the name of some method used by the framework users will see a message explaining what type of object was expected. Only active in test and development environments by default #1209 [Michael Koziarski]
+
+* Fixed the test_helper.rb to be safe for requiring controllers from multiple spots, like app/controllers/article_controller.rb and app/controllers/admin/article_controller.rb, without reloading the environment twice #1390 [Nicholas Seckar]
+
+* Fixed Webrick to escape + characters in URL's the same way that lighttpd and apache do #1397 [Nicholas Seckar]
+
+* Added -e/--environment option to script/runner #1408 [fbeausoleil@ftml.net]
+
+* Modernize the scaffold generator to use the simplified render and test methods and to change style from @params["id"] to params[:id]. #1367
+
+* Added graceful exit from pressing CTRL-C during the run of the rails command #1150 [Caleb Tennis]
+
+* Allow graceful exits for dispatch.fcgi processes by sending a SIGUSR1. If the process is currently handling a request, the request will be allowed to complete and then will terminate itself. If a request is not being handled, the process is terminated immediately (via #exit). This basically works like restart graceful on Apache. [Jamis Buck]
+
+* Made dispatch.fcgi more robust by catching fluke errors and retrying unless its a permanent condition. [Jamis Buck]
+
+* Added console --profile for profiling an IRB session #1154 [Jeremy Kemper]
+
+* Changed console_sandbox into console --sandbox #1154 [Jeremy Kemper]
+
+
+*0.12.1* (20th April, 2005)
+
+* Upgraded to Active Record 1.10.1, Action Pack 1.8.1, Action Mailer 0.9.1, Action Web Service 0.7.1
+
+
+*0.12.0* (19th April, 2005)
+
+* Fixed that purge_test_database would use database settings from the development environment when recreating the test database #1122 [rails@cogentdude.com]
+
+* Added script/benchmarker to easily benchmark one or more statement a number of times from within the environment. Examples:
+
+ # runs the one statement 10 times
+ script/benchmarker 10 'Person.expensive_method(10)'
+
+ # pits the two statements against each other with 50 runs each
+ script/benchmarker 50 'Person.expensive_method(10)' 'Person.cheap_method(10)'
+
+* Added script/profiler to easily profile a single statement from within the environment. Examples:
+
+ script/profiler 'Person.expensive_method(10)'
+ script/profiler 'Person.expensive_method(10)' 10 # runs the statement 10 times
+
+* Added Rake target clear_logs that'll truncate all the *.log files in log/ to zero #1079 [Lucas Carlson]
+
+* Added lazy typing for generate, such that ./script/generate cn == ./script/generate controller and the likes #1051 [k@v2studio.com]
+
+* Fixed that ownership is brought over in pg_dump during tests for PostgreSQL #1060 [pburleson@gmail.com]
+
+* Upgraded to Active Record 1.10.0, Action Pack 1.8.0, Action Mailer 0.9.0, Action Web Service 0.7.0, Active Support 1.0.4
+
+
+*0.11.1* (27th March, 2005)
+
+* Fixed the dispatch.fcgi use of a logger
+
+* Upgraded to Active Record 1.9.1, Action Pack 1.7.0, Action Mailer 0.8.1, Action Web Service 0.6.2, Active Support 1.0.3
+
+
+*0.11.0* (22th March, 2005)
+
+* Removed SCRIPT_NAME from the WEBrick environment to prevent conflicts with PATH_INFO #896 [Nicholas Seckar]
+
+* Removed ?$1 from the dispatch.f/cgi redirect line to get rid of 'complete/path/from/request.html' => nil being in the @params now that the ENV["REQUEST_URI"] is used to determine the path #895 [dblack/Nicholas Seckar]
+
+* Added additional error handling to the FastCGI dispatcher to catch even errors taking down the entire process
+
+* Improved the generated scaffold code a lot to take advantage of recent Rails developments #882 [Tobias Luetke]
+
+* Combined the script/environment.rb used for gems and regular files version. If vendor/rails/* has all the frameworks, then files version is used, otherwise gems #878 [Nicholas Seckar]
+
+* Changed .htaccess to allow dispatch.* to be called from a sub-directory as part of the push with Action Pack to make Rails work on non-vhost setups #826 [Nicholas Seckar/Tobias Luetke]
+
+* Added script/runner which can be used to run code inside the environment by eval'ing the first parameter. Examples:
+
+ ./script/runner 'ReminderService.deliver'
+ ./script/runner 'Mailer.receive(STDIN.read)'
+
+ This makes it easier to do CRON and postfix scripts without actually making a script just to trigger 1 line of code.
+
+* Fixed webrick_server cookie handling to allow multiple cookes to be set at once #800, #813 [dave@cherryville.org]
+
+* Fixed the Rakefile's interaction with postgresql to:
+
+ 1. Use PGPASSWORD and PGHOST in the environment to fix prompting for
+ passwords when connecting to a remote db and local socket connections.
+ 2. Add a '-x' flag to pg_dump which stops it dumping privileges #807 [rasputnik]
+ 3. Quote the user name and use template0 when dumping so the functions doesn't get dumped too #855 [pburleson]
+ 4. Use the port if available #875 [madrobby]
+
+* Upgraded to Active Record 1.9.0, Action Pack 1.6.0, Action Mailer 0.8.0, Action Web Service 0.6.1, Active Support 1.0.2
+
+
+*0.10.1* (7th March, 2005)
+
+* Fixed rake stats to ignore editor backup files like model.rb~ #791 [skanthak]
+
+* Added exception shallowing if the DRb server can't be started (not worth making a fuss about to distract new users) #779 [Tobias Luetke]
+
+* Added an empty favicon.ico file to the public directory of new applications (so the logs are not spammed by its absence)
+
+* Fixed that scaffold generator new template should use local variable instead of instance variable #778 [Dan Peterson]
+
+* Allow unit tests to run on a remote server for PostgreSQL #781 [adamm@galacticasoftware.com]
+
+* Added web_service generator (run ./script/generate web_service for help) #776 [Leon Bredt]
+
+* Added app/apis and components to code statistics report #729 [Scott Barron]
+
+* Fixed WEBrick server to use ABSOLUTE_RAILS_ROOT instead of working_directory #687 [Nicholas Seckar]
+
+* Fixed rails_generator to be usable without RubyGems #686 [Cristi BALAN]
+
+* Fixed -h/--help for generate and destroy generators #331
+
+* Added begin/rescue around the FCGI dispatcher so no uncaught exceptions can bubble up to kill the process (logs to log/fastcgi.crash.log)
+
+* Fixed that association#count would produce invalid sql when called sequentialy #659 [kanis@comcard.de]
+
+* Fixed test/mocks/testing to the correct test/mocks/test #740
+
+* Added early failure if the Ruby version isn't 1.8.2 or above #735
+
+* Removed the obsolete -i/--index option from the WEBrick servlet #743
+
+* Upgraded to Active Record 1.8.0, Action Pack 1.5.1, Action Mailer 0.7.1, Action Web Service 0.6.0, Active Support 1.0.1
+
+
+*0.10.0* (24th February, 2005)
+
+* Changed default IP binding for WEBrick from 127.0.0.1 to 0.0.0.0 so that the server is accessible both locally and remotely #696 [Marcel]
+
+* Fixed that script/server -d was broken so daemon mode couldn't be used #687 [Nicholas Seckar]
+
+* Upgraded to breakpoint 92 which fixes:
+
+ * overload IRB.parse_opts(), fixes #443
+ => breakpoints in tests work even when running them via rake
+ * untaint handlers, might fix an issue discussed on the Rails ML
+ * added verbose mode to breakpoint_client
+ * less noise caused by breakpoint_client by default
+ * ignored TerminateLineInput exception in signal handler
+ => quiet exit on Ctrl-C
+
+* Added support for independent components residing in /components. Example:
+
+ Controller: components/list/items_controller.rb
+ (holds a List::ItemsController class with uses_component_template_root called)
+
+ Model : components/list/item.rb
+ (namespace is still shared, so an Item model in app/models will take precedence)
+
+ Views : components/list/items/show.rhtml
+
+
+* Added --sandbox option to script/console that'll roll back all changes made to the database when you quit #672 [Jeremy Kemper]
+
+* Added 'recent' as a rake target that'll run tests for files that changed in the last 10 minutes #612 [Jeremy Kemper]
+
+* Changed script/console to default to development environment and drop --no-inspect #650 [Jeremy Kemper]
+
+* Added that the 'fixture :posts' syntax can be used for has_and_belongs_to_many fixtures where a model doesn't exist #572 [Jeremy Kemper]
+
+* Added that running test_units and test_functional now performs the clone_structure_to_test as well #566 [rasputnik]
+
+* Added new generator framework that informs about its doings on generation and enables updating and destruction of generated artifacts. See the new script/destroy and script/update for more details #487 [Jeremy Kemper]
+
+* Added Action Web Service as a new add-on framework for Action Pack [Leon Bredt]
+
+* Added Active Support as an independent utility and standard library extension bundle
+
+* Upgraded to Active Record 1.7.0, Action Pack 1.5.0, Action Mailer 0.7.0
+
+
+*0.9.5* (January 25th, 2005)
+
+* Fixed dependency reloading by switching to a remove_const approach where all Active Records, Active Record Observers, and Action Controllers are reloading by undefining their classes. This enables you to remove methods in all three types and see the change reflected immediately and it fixes #539. This also means that only those three types of classes will benefit from the const_missing and reloading approach. If you want other classes (like some in lib/) to reload, you must use require_dependency to do it.
+
+* Added Florian Gross' latest version of Breakpointer and friends that fixes a variaty of bugs #441 [Florian Gross]
+
+* Fixed skeleton Rakefile to work with sqlite3 out of the box #521 [rasputnik]
+
+* Fixed that script/breakpointer didn't get the Ruby path rewritten as the other scripts #523 [brandt@kurowski.net]
+
+* Fixed handling of syntax errors in models that had already been succesfully required once in the current interpreter
+
+* Fixed that models that weren't referenced in associations weren't being reloaded in the development mode by reinstating the reload
+
+* Fixed that generate scaffold would produce bad functional tests
+
+* Fixed that FCGI can also display SyntaxErrors
+
+* Upgraded to Active Record 1.6.0, Action Pack 1.4.0
+
+
+*0.9.4.1* (January 18th, 2005)
+
+* Added 5-second timeout to WordNet alternatives on creating reserved-word models #501 [Marcel Molina]
+
+* Fixed binding of caller #496 [Alexey]
+
+* Upgraded to Active Record 1.5.1, Action Pack 1.3.1, Action Mailer 0.6.1
+
+
+*0.9.4* (January 17th, 2005)
+
+* Added that ApplicationController will catch a ControllerNotFound exception if someone attempts to access a url pointing to an unexisting controller [Tobias Luetke]
+
+* Flipped code-to-test ratio around to be more readable #468 [Scott Baron]
+
+* Fixed log file permissions to be 666 instead of 777 (so they're not executable) #471 [Lucas Carlson]
+
+* Fixed that auto reloading would some times not work or would reload the models twice #475 [Tobias Luetke]
+
+* Added rewrite rules to deal with caching to public/.htaccess
+
+* Added the option to specify a controller name to "generate scaffold" and made the default controller name the plural form of the model.
+
+* Added that rake clone_structure_to_test, db_structure_dump, and purge_test_database tasks now pick up the source database to use from
+ RAILS_ENV instead of just forcing development #424 [Tobias Luetke]
+
+* Fixed script/console to work with Windows (that requires the use of irb.bat) #418 [octopod]
+
+* Fixed WEBrick servlet slowdown over time by restricting the load path reloading to mod_ruby
+
+* Removed Fancy Indexing as a default option on the WEBrick servlet as it made it harder to use various caching schemes
+
+* Upgraded to Active Record 1.5, Action Pack 1.3, Action Mailer 0.6
+
+
+*0.9.3* (January 4th, 2005)
+
+* Added support for SQLite in the auto-dumping/importing of schemas for development -> test #416
+
+* Added automated rewriting of the shebang lines on installs through the gem rails command #379 [Manfred Stienstra]
+
+* Added ActionMailer::Base.deliver_method = :test to the test environment so that mail objects are available in ActionMailer::Base.deliveries
+ for functional testing.
+
+* Added protection for creating a model through the generators with a name of an existing class, like Thread or Date.
+ It'll even offer you a synonym using wordnet.princeton.edu as a look-up. No, I'm not kidding :) [Florian Gross]
+
+* Fixed dependency management to happen in a unified fashion for Active Record and Action Pack using the new Dependencies module. This means that
+ the environment options needs to change from:
+
+ Before in development.rb:
+ ActionController::Base.reload_dependencies = true  
+ ActiveRecord::Base.reload_associations     = true
+
+ Now in development.rb:
+ Dependencies.mechanism = :load
+
+ Before in production.rb and test.rb:
+ ActionController::Base.reload_dependencies = false
+ ActiveRecord::Base.reload_associations     = false
+
+ Now in production.rb and test.rb:
+ Dependencies.mechanism = :require
+
+* Fixed problems with dependency caching and controller hierarchies on Ruby 1.8.2 in development mode #351
+
+* Fixed that generated action_mailers doesnt need to require the action_mailer since thats already done in the environment #382 [Lucas Carlson]
+
+* Upgraded to Action Pack 1.2.0 and Active Record 1.4.0
+
+
+*0.9.2*
+
+* Fixed CTRL-C exists from the Breakpointer to be a clean affair without error dumping [Kent Sibilev]
+
+* Fixed "rake stats" to work with sub-directories in models and controllers and to report the code to test ration [Scott Baron]
+
+* Added that Active Record associations are now reloaded instead of cleared to work with the new const_missing hook in Active Record.
+
+* Added graceful handling of an inaccessible log file by redirecting output to STDERR with a warning #330 [rainmkr]
+
+* Added support for a -h/--help parameter in the generator #331 [Ulysses]
+
+* Fixed that File.expand_path in config/environment.rb would fail when dealing with symlinked public directories [mjobin]
+
+* Upgraded to Action Pack 1.1.0 and Active Record 1.3.0
+
+
+*0.9.1*
+
+* Upgraded to Action Pack 1.0.1 for important bug fix
+
+* Updated gem dependencies
+
+
+*0.9.0*
+
+* Renamed public/dispatch.servlet to script/server -- it wasn't really dispatching anyway as its delegating calls to public/dispatch.rb
+
+* Renamed AbstractApplicationController and abstract_application.rb to ApplicationController and application.rb, so that it will be possible
+ for the framework to automatically pick up on app/views/layouts/application.rhtml and app/helpers/application.rb
+
+* Added script/console that makes it even easier to start an IRB session for interacting with the domain model. Run with no-args to
+ see help.
+
+* Added breakpoint support through the script/breakpointer client. This means that you can break out of execution at any point in
+ the code, investigate and change the model, AND then resume execution! Example:
+
+ class WeblogController < ActionController::Base
+ def index
+ @posts = Post.find_all
+ breakpoint "Breaking out from the list"
+ end
+ end
+
+ So the controller will accept the action, run the first line, then present you with a IRB prompt in the breakpointer window.
+ Here you can do things like:
+
+ Executing breakpoint "Breaking out from the list" at .../webrick_server.rb:16 in 'breakpoint'
+
+ >> @posts.inspect
+ => "[#<Post:0x14a6be8 @attributes={\"title\"=>nil, \"body\"=>nil, \"id\"=>\"1\"}>,
+ #<Post:0x14a6620 @attributes={\"title\"=>\"Rails you know!\", \"body\"=>\"Only ten..\", \"id\"=>\"2\"}>]"
+ >> @posts.first.title = "hello from a breakpoint"
+ => "hello from a breakpoint"
+
+ ...and even better is that you can examine how your runtime objects actually work:
+
+ >> f = @posts.first
+ => #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>
+ >> f.
+ Display all 152 possibilities? (y or n)
+
+ Finally, when you're ready to resume execution, you press CTRL-D
+
+* Changed environments to be configurable through an environment variable. By default, the environment is "development", but you
+ can change that and set your own by configuring the Apache vhost with a string like (mod_env must be available on the server):
+
+ SetEnv RAILS_ENV production
+
+ ...if you're using WEBrick, you can pick the environment to use with the command-line parameters -e/--environment, like this:
+
+ ruby public/dispatcher.servlet -e production
+
+* Added a new default environment called "development", which leaves the production environment to be tuned exclusively for that.
+
+* Added a start_server in the root of the Rails application to make it even easier to get started
+
+* Fixed public/.htaccess to use RewriteBase and share the same rewrite rules for all the dispatch methods
+
+* Fixed webrick_server to handle requests in a serialized manner (the Rails reloading infrastructure is not thread-safe)
+
+* Added support for controllers in directories. So you can have:
+
+ app/controllers/account_controller.rb # URL: /account/
+ app/controllers/admin/account_controller.rb # URL: /admin/account/
+
+ NOTE: You need to update your public/.htaccess with the new rules to pick it up
+
+* Added reloading for associations and dependencies under cached environments like FastCGI and mod_ruby. This makes it possible to use
+ those environments for development. This is turned on by default, but can be turned off with
+ ActiveRecord::Base.reload_associations = false and ActionController::Base.reload_dependencies = false in production environments.
+
+* Added support for sub-directories in app/models. So now you can have something like Basecamp with:
+
+ app/models/accounting
+ app/models/project
+ app/models/participants
+ app/models/settings
+
+ It's poor man's namespacing, but only for file-system organization. You still require files just like before.
+ Nothing changes inside the files themselves.
+
+
+* Fixed a few references in the tests generated by new_mailer [Jeremy Kemper]
+
+* Added support for mocks in testing with test/mocks
+
+* Cleaned up the environments a bit and added global constant RAILS_ROOT
+
+
+*0.8.5* (9)
+
+* Made dev-util available to all tests, so you can insert breakpoints in any test case to get an IRB prompt at that point [Jeremy Kemper]:
+
+ def test_complex_stuff
+ @david.projects << @new_project
+ breakpoint "Let's have a closer look at @david"
+ end
+
+ You need to install dev-utils yourself for this to work ("gem install dev-util").
+
+* Added shared generator behavior so future upgrades should be possible without manually copying over files [Jeremy Kemper]
+
+* Added the new helper style to both controller and helper templates [Jeremy Kemper]
+
+* Added new_crud generator for creating a model and controller at the same time with explicit scaffolding [Jeremy Kemper]
+
+* Added configuration of Test::Unit::TestCase.fixture_path to test_helper to concide with the new AR fixtures style
+
+* Fixed that new_model was generating singular table/fixture names
+
+* Upgraded to Action Mailer 0.4.0
+
+* Upgraded to Action Pack 0.9.5
+
+* Upgraded to Active Record 1.1.0
+
+
+*0.8.0 (15)*
+
+* Removed custom_table_name option for new_model now that the Inflector is as powerful as it is
+
+* Changed the default rake action to just do testing and separate API generation and coding statistics into a "doc" task.
+
+* Fixed WEBrick dispatcher to handle missing slashes in the URLs gracefully [alexey]
+
+* Added user option for all postgresql tool calls in the rakefile [elvstone]
+
+* Fixed problem with running "ruby public/dispatch.servlet" instead of "cd public; ruby dispatch.servlet" [alexey]
+
+* Fixed WEBrick server so that it no longer hardcodes the ruby interpreter used to "ruby" but will get the one used based
+ on the Ruby runtime configuration. [Marcel Molina Jr.]
+
+* Fixed Dispatcher so it'll route requests to magic_beans to MagicBeansController/magic_beans_controller.rb [Caio Chassot]
+
+* "new_controller MagicBeans" and "new_model SubscriptionPayments" will now both behave properly as they use the new Inflector.
+
+* Fixed problem with MySQL foreign key constraint checks in Rake :clone_production_structure_to_test target [Andreas Schwarz]
+
+* Changed WEBrick server to by default be auto-reloading, which is slower but makes source changes instant.
+ Class compilation cache can be turned on with "-c" or "--cache-classes".
+
+* Added "-b/--binding" option to WEBrick dispatcher to bind the server to a specific IP address (default: 127.0.0.1) [Kevin Temp]
+
+* dispatch.fcgi now DOESN'T set FCGI_PURE_RUBY as it was slowing things down for now reason [Andreas Schwarz]
+
+* Added new_mailer generator to work with Action Mailer
+
+* Included new framework: Action Mailer 0.3
+
+* Upgraded to Action Pack 0.9.0
+
+* Upgraded to Active Record 1.0.0
+
+
+*0.7.0*
+
+* Added an optional second argument to the new_model script that allows the programmer to specify the table name,
+ which will used to generate a custom table_name method in the model and will also be used in the creation of fixtures.
+ [Kevin Radloff]
+
+* script/new_model now turns AccountHolder into account_holder instead of accountholder [Kevin Radloff]
+
+* Fixed the faulty handleing of static files with WEBrick [Andreas Schwarz]
+
+* Unified function_test_helper and unit_test_helper into test_helper
+
+* Fixed bug with the automated production => test database dropping on PostgreSQL [dhawkins]
+
+* create_fixtures in both the functional and unit test helper now turns off the log during fixture generation
+ and can generate more than one fixture at a time. Which makes it possible for assignments like:
+
+ @people, @projects, @project_access, @companies, @accounts =
+ create_fixtures "people", "projects", "project_access", "companies", "accounts"
+
+* Upgraded to Action Pack 0.8.5 (locally-scoped variables, partials, advanced send_file)
+
+* Upgraded to Active Record 0.9.5 (better table_name guessing, cloning, find_all_in_collection)
+
+
+*0.6.5*
+
+* No longer specifies a template for rdoc, so it'll use whatever is default (you can change it in the rakefile)
+
+* The new_model generator will now use the same rules for plural wordings as Active Record
+ (so Category will give categories, not categorys) [Kevin Radloff]
+
+* dispatch.fcgi now sets FCGI_PURE_RUBY to true to ensure that it's the Ruby version that's loaded [danp]
+
+* Made the GEM work with Windows
+
+* Fixed bug where mod_ruby would "forget" the load paths added when switching between controllers
+
+* PostgreSQL are now supported for the automated production => test database dropping [Kevin Radloff]
+
+* Errors thrown by the dispatcher are now properly handled in FCGI.
+
+* Upgraded to Action Pack 0.8.0 (lots and lots and lots of fixes)
+
+* Upgraded to Active Record 0.9.4 (a bunch of fixes)
+
+
+*0.6.0*
+
+* Added AbstractionApplicationController as a superclass for all controllers generated. This class can be used
+ to carry filters and methods that are to be shared by all. It has an accompanying ApplicationHelper that all
+ controllers will also automatically have available.
+
+* Added environments that can be included from any script to get the full Active Record and Action Controller
+ context running. This can be used by maintenance scripts or to interact with the model through IRB. Example:
+
+ require 'config/environments/production'
+
+ for account in Account.find_all
+ account.recalculate_interests
+ end
+
+ A short migration script for an account model that had it's interest calculation strategy changed.
+
+* Accessing the index of a controller with "/weblog" will now redirect to "/weblog/" (only on Apache, not WEBrick)
+
+* Simplified the default Apache config so even remote requests are served off CGI as a default.
+ You'll now have to do something specific to activate mod_ruby and FCGI (like using the force urls).
+ This should make it easier for new comers that start on an external server.
+
+* Added more of the necessary Apache options to .htaccess to make it easier to setup
+
+* Upgraded to Action Pack 0.7.9 (lots of fixes)
+
+* Upgraded to Active Record 0.9.3 (lots of fixes)
+
+
+*0.5.7*
+
+* Fixed bug in the WEBrick dispatcher that prevented it from getting parameters from the URL
+ (through GET requests or otherwise)
+
+* Added lib in root as a place to store app specific libraries
+
+* Added lib and vendor to load_path, so anything store within can be loaded directly.
+ Hence lib/redcloth.rb can be loaded with require "redcloth"
+
+* Upgraded to Action Pack 0.7.8 (lots of fixes)
+
+* Upgraded to Active Record 0.9.2 (minor upgrade)
+
+
+*0.5.6*
+
+* Upgraded to Action Pack 0.7.7 (multipart form fix)
+
+* Updated the generated template stubs to valid XHTML files
+
+* Ensure that controllers generated are capitalized, so "new_controller TodoLists"
+ gives the same as "new_controller Todolists" and "new_controller todolists".
+
+
+*0.5.5*
+
+* Works on Windows out of the box! (Dropped symlinks)
+
+* Added webrick dispatcher: Try "ruby public/dispatch.servlet --help" [Florian Gross]
+
+* Report errors about initialization to browser (instead of attempting to use uninitialized logger)
+
+* Upgraded to Action Pack 0.7.6
+
+* Upgraded to Active Record 0.9.1
+
+* Added distinct 500.html instead of reusing 404.html
+
+* Added MIT license
+
+
+*0.5.0*
+
+* First public release
diff --git a/vendor/rails-2.0.2/railties/MIT-LICENSE b/vendor/rails-2.0.2/railties/MIT-LICENSE
new file mode 100644
index 000000000..5fee6e106
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/MIT-LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2004-2007 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. \ No newline at end of file
diff --git a/vendor/rails-2.0.2/railties/README b/vendor/rails-2.0.2/railties/README
new file mode 100644
index 000000000..a1db73c4b
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/README
@@ -0,0 +1,203 @@
+== Welcome to Rails
+
+Rails is a web-application and persistence framework that includes everything
+needed to create database-backed web-applications according to the
+Model-View-Control pattern of separation. 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, start a new Rails application using the <tt>rails</tt> command
+ and your application name. Ex: rails myapp
+ (If you've downloaded Rails in a complete tgz or zip, this step is already done)
+2. Change directory into myapp and start the web server: <tt>script/server</tt> (run with --help for options)
+3. Go to http://localhost:3000/ and get "Welcome aboard: You’re riding the Rails!"
+4. Follow the guidelines to start developing your application
+
+
+== Web Servers
+
+By default, Rails will try to use Mongrel and lighttpd if they are installed, otherwise
+Rails will use WEBrick, the webserver that ships with Ruby. When you run script/server,
+Rails will check if Mongrel exists, then lighttpd and finally fall back to WEBrick. This ensures
+that you can always get up and running quickly.
+
+Mongrel is a Ruby-based webserver with a C component (which requires compilation) that is
+suitable for development and deployment of Rails applications. If you have Ruby Gems installed,
+getting up and running with mongrel is as easy as: <tt>gem install mongrel</tt>.
+More info at: http://mongrel.rubyforge.org
+
+If Mongrel is not installed, Rails will look for lighttpd. It's considerably faster than
+Mongrel and WEBrick and also suited for production use, but requires additional
+installation and currently only works well on OS X/Unix (Windows users are encouraged
+to start with Mongrel). We recommend version 1.4.11 and higher. You can download it from
+http://www.lighttpd.net.
+
+And finally, if neither Mongrel or lighttpd are installed, Rails will use the built-in Ruby
+web server, WEBrick. WEBrick is a small Ruby web server suitable for development, but not
+for production.
+
+But of course its also possible to run Rails on any platform that supports FCGI.
+Apache, LiteSpeed, IIS are just a few. For more information on FCGI,
+please visit: http://wiki.rubyonrails.com/rails/pages/FastCGI
+
+
+== 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/ including:
+
+* The Learning Ruby (Pickaxe) Book: http://www.ruby-doc.org/docs/ProgrammingRuby/
+* Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide)
+
+These two online (and free) 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! 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
+ => "[#<Post:0x14a6be8 @attributes={\"title\"=>nil, \"body\"=>nil, \"id\"=>\"1\"}>,
+ #<Post:0x14a6620 @attributes={\"title\"=>\"Rails you know!\", \"body\"=>\"Only ten..\", \"id\"=>\"2\"}>]"
+ >> @posts.first.title = "hello from a debugger"
+ => "hello from a debugger"
+
+...and even better is that you can examine how your runtime objects actually work:
+
+ >> f = @posts.first
+ => #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>
+ >> f.
+ Display all 152 possibilities? (y or n)
+
+Finally, when you're ready to resume execution, you enter "cont"
+
+
+== Console
+
+You can interact with the domain model by starting the console through <tt>script/console</tt>.
+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.
+Passing an argument will specify a different environment, like <tt>script/console production</tt>.
+
+To reload your controllers and models after launching the console run <tt>reload!</tt>
+
+
+== Description of Contents
+
+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.
+ Most models will descend from ActiveRecord::Base.
+
+app/views
+ Holds the template files for the view that should be named like
+ weblogs/index.erb for the WeblogsController#index action. All views use eRuby
+ syntax.
+
+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
+ <tt>layout :default</tt> and create a file named default.erb. Inside default.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 script/generate 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 <tt>rake doc:app</tt>
+
+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 script/generate scripts, 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.
+ This directory is in the load path.
diff --git a/vendor/rails-2.0.2/railties/Rakefile b/vendor/rails-2.0.2/railties/Rakefile
new file mode 100644
index 000000000..3a263d566
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/Rakefile
@@ -0,0 +1,358 @@
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+require 'rake/gempackagetask'
+require 'rake/contrib/rubyforgepublisher'
+
+require 'date'
+require 'rbconfig'
+
+require File.join(File.dirname(__FILE__), 'lib/rails', 'version')
+
+PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
+PKG_NAME = 'rails'
+PKG_VERSION = Rails::VERSION::STRING + PKG_BUILD
+PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
+PKG_DESTINATION = ENV["RAILS_PKG_DESTINATION"] || "../#{PKG_NAME}"
+
+RELEASE_NAME = "REL #{PKG_VERSION}"
+
+RUBY_FORGE_PROJECT = "rails"
+RUBY_FORGE_USER = "webster132"
+
+
+task :default => :test
+
+## This is required until the regular test task
+## below passes. It's not ideal, but at least
+## we can see the failures
+task :test do
+ Dir['test/**/*_test.rb'].all? do |file|
+ system("ruby #{file}")
+ end or raise "Failures"
+end
+
+Rake::TestTask.new("regular_test") do |t|
+ t.libs << 'test'
+ t.pattern = 'test/**/*_test.rb'
+ t.warning = true
+ t.verbose = true
+end
+
+
+BASE_DIRS = %w(
+ app
+ config/environments
+ config/initializers
+ components
+ db
+ doc
+ log
+ lib
+ lib/tasks
+ public
+ script
+ script/performance
+ script/process
+ test
+ vendor
+ vendor/plugins
+ tmp/sessions
+ tmp/cache
+ tmp/sockets
+ tmp/pids
+)
+
+APP_DIRS = %w( models controllers helpers views views/layouts )
+PUBLIC_DIRS = %w( images javascripts stylesheets )
+TEST_DIRS = %w( fixtures unit functional mocks mocks/development mocks/test )
+
+LOG_FILES = %w( server.log development.log test.log production.log )
+HTML_FILES = %w( 422.html 404.html 500.html index.html robots.txt favicon.ico images/rails.png
+ javascripts/prototype.js javascripts/application.js
+ javascripts/effects.js javascripts/dragdrop.js javascripts/controls.js )
+BIN_FILES = %w( about console destroy generate performance/benchmarker performance/profiler process/reaper process/spawner process/inspector runner server plugin )
+
+VENDOR_LIBS = %w( actionpack activerecord actionmailer activesupport activeresource railties )
+
+
+desc "Generates a fresh Rails package with documentation"
+task :fresh_rails => [ :clean, :make_dir_structure, :initialize_file_stubs, :copy_vendor_libraries, :copy_ties_content, :generate_documentation ]
+
+desc "Generates a fresh Rails package using GEMs with documentation"
+task :fresh_gem_rails => [ :clean, :make_dir_structure, :initialize_file_stubs, :copy_ties_content, :copy_gem_environment ]
+
+desc "Generates a fresh Rails package without documentation (faster)"
+task :fresh_rails_without_docs => [ :clean, :make_dir_structure, :initialize_file_stubs, :copy_vendor_libraries, :copy_ties_content ]
+
+desc "Generates a fresh Rails package without documentation (faster)"
+task :fresh_rails_without_docs_using_links => [ :clean, :make_dir_structure, :initialize_file_stubs, :link_vendor_libraries, :copy_ties_content ]
+
+desc "Generates minimal Rails package using symlinks"
+task :dev => [ :clean, :make_dir_structure, :initialize_file_stubs, :link_vendor_libraries, :copy_ties_content ]
+
+desc "Packages the fresh Rails package with documentation"
+task :package => [ :clean, :fresh_rails ] do
+ system %{cd ..; tar -czvf #{PKG_NAME}-#{PKG_VERSION}.tgz #{PKG_NAME}}
+ system %{cd ..; zip -r #{PKG_NAME}-#{PKG_VERSION}.zip #{PKG_NAME}}
+end
+
+task :clean do
+ rm_rf PKG_DESTINATION
+end
+
+# Get external spinoffs -------------------------------------------------------------------
+
+desc "Updates railties to the latest version of the javascript spinoffs"
+task :update_js do
+ for js in %w( prototype controls dragdrop effects )
+ rm "html/javascripts/#{js}.js"
+ cp "./../actionpack/lib/action_view/helpers/javascripts/#{js}.js", "html/javascripts"
+ end
+end
+
+# Make directory structure ----------------------------------------------------------------
+
+def make_dest_dirs(dirs, path = '.')
+ mkdir_p dirs.map { |dir| File.join(PKG_DESTINATION, path.to_s, dir) }
+end
+
+desc "Make the directory structure for the new Rails application"
+task :make_dir_structure => [ :make_base_dirs, :make_app_dirs, :make_public_dirs, :make_test_dirs ]
+
+task(:make_base_dirs) { make_dest_dirs BASE_DIRS }
+task(:make_app_dirs) { make_dest_dirs APP_DIRS, 'app' }
+task(:make_public_dirs) { make_dest_dirs PUBLIC_DIRS, 'public' }
+task(:make_test_dirs) { make_dest_dirs TEST_DIRS, 'test' }
+
+
+# Initialize file stubs -------------------------------------------------------------------
+
+desc "Initialize empty file stubs (such as for logging)"
+task :initialize_file_stubs => [ :initialize_log_files ]
+
+task :initialize_log_files do
+ log_dir = File.join(PKG_DESTINATION, 'log')
+ chmod 0777, log_dir
+ LOG_FILES.each do |log_file|
+ log_path = File.join(log_dir, log_file)
+ touch log_path
+ chmod 0666, log_path
+ end
+end
+
+
+# Copy Vendors ----------------------------------------------------------------------------
+
+desc "Copy in all the Rails packages to vendor"
+task :copy_vendor_libraries do
+ mkdir File.join(PKG_DESTINATION, 'vendor', 'rails')
+ VENDOR_LIBS.each { |dir| cp_r File.join('..', dir), File.join(PKG_DESTINATION, 'vendor', 'rails', dir) }
+ FileUtils.rm_r(Dir.glob(File.join(PKG_DESTINATION, 'vendor', 'rails', "**", ".svn")))
+end
+
+desc "Link in all the Rails packages to vendor"
+task :link_vendor_libraries do
+ mkdir File.join(PKG_DESTINATION, 'vendor', 'rails')
+ VENDOR_LIBS.each { |dir| ln_s File.join('..', '..', '..', dir), File.join(PKG_DESTINATION, 'vendor', 'rails', dir) }
+end
+
+
+# Copy Ties Content -----------------------------------------------------------------------
+
+# :link_apache_config
+desc "Make copies of all the default content of ties"
+task :copy_ties_content => [
+ :copy_rootfiles, :copy_dispatches, :copy_html_files, :copy_application,
+ :copy_configs, :copy_binfiles, :copy_test_helpers, :copy_app_doc_readme ]
+
+task :copy_dispatches do
+ copy_with_rewritten_ruby_path("dispatches/dispatch.rb", "#{PKG_DESTINATION}/public/dispatch.rb")
+ chmod 0755, "#{PKG_DESTINATION}/public/dispatch.rb"
+
+ copy_with_rewritten_ruby_path("dispatches/dispatch.rb", "#{PKG_DESTINATION}/public/dispatch.cgi")
+ chmod 0755, "#{PKG_DESTINATION}/public/dispatch.cgi"
+
+ copy_with_rewritten_ruby_path("dispatches/dispatch.fcgi", "#{PKG_DESTINATION}/public/dispatch.fcgi")
+ chmod 0755, "#{PKG_DESTINATION}/public/dispatch.fcgi"
+
+ # copy_with_rewritten_ruby_path("dispatches/gateway.cgi", "#{PKG_DESTINATION}/public/gateway.cgi")
+ # chmod 0755, "#{PKG_DESTINATION}/public/gateway.cgi"
+end
+
+task :copy_html_files do
+ HTML_FILES.each { |file| cp File.join('html', file), File.join(PKG_DESTINATION, 'public', file) }
+end
+
+task :copy_application do
+ cp "helpers/application.rb", "#{PKG_DESTINATION}/app/controllers/application.rb"
+ cp "helpers/application_helper.rb", "#{PKG_DESTINATION}/app/helpers/application_helper.rb"
+end
+
+task :copy_configs do
+ app_name = "rails"
+ socket = nil
+ require 'erb'
+ File.open("#{PKG_DESTINATION}/config/database.yml", 'w') {|f| f.write ERB.new(IO.read("configs/databases/mysql.yml"), nil, '-').result(binding)}
+
+ cp "configs/routes.rb", "#{PKG_DESTINATION}/config/routes.rb"
+
+ cp "configs/apache.conf", "#{PKG_DESTINATION}/public/.htaccess"
+
+ cp "configs/initializers/inflections.rb", "#{PKG_DESTINATION}/config/initializers/inflections.rb"
+ cp "configs/initializers/mime_types.rb", "#{PKG_DESTINATION}/config/initializers/mime_types.rb"
+
+ cp "environments/boot.rb", "#{PKG_DESTINATION}/config/boot.rb"
+ cp "environments/environment.rb", "#{PKG_DESTINATION}/config/environment.rb"
+ cp "environments/production.rb", "#{PKG_DESTINATION}/config/environments/production.rb"
+ cp "environments/development.rb", "#{PKG_DESTINATION}/config/environments/development.rb"
+ cp "environments/test.rb", "#{PKG_DESTINATION}/config/environments/test.rb"
+end
+
+task :copy_binfiles do
+ BIN_FILES.each do |file|
+ dest_file = File.join(PKG_DESTINATION, 'script', file)
+ copy_with_rewritten_ruby_path(File.join('bin', file), dest_file)
+ chmod 0755, dest_file
+ end
+end
+
+task :copy_rootfiles do
+ cp "fresh_rakefile", "#{PKG_DESTINATION}/Rakefile"
+ cp "README", "#{PKG_DESTINATION}/README"
+ cp "CHANGELOG", "#{PKG_DESTINATION}/CHANGELOG"
+end
+
+task :copy_test_helpers do
+ cp "helpers/test_helper.rb", "#{PKG_DESTINATION}/test/test_helper.rb"
+end
+
+task :copy_app_doc_readme do
+ cp "doc/README_FOR_APP", "#{PKG_DESTINATION}/doc/README_FOR_APP"
+end
+
+task :link_apache_config do
+ chdir(File.join(PKG_DESTINATION, 'config')) {
+ ln_s "../public/.htaccess", "apache.conf"
+ }
+end
+
+def copy_with_rewritten_ruby_path(src_file, dest_file)
+ ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])
+
+ File.open(dest_file, 'w') do |df|
+ File.open(src_file) do |sf|
+ line = sf.gets
+ if (line =~ /#!.+ruby\s*/) != nil
+ df.puts("#!#{ruby}")
+ else
+ df.puts(line)
+ end
+ df.write(sf.read)
+ end
+ end
+end
+
+
+# Generate documentation ------------------------------------------------------------------
+
+desc "Generate documentation for the framework and for the empty application"
+task :generate_documentation => [ :generate_app_doc, :generate_rails_framework_doc ]
+
+task :generate_rails_framework_doc do
+ system %{cd #{PKG_DESTINATION}; rake doc:rails}
+end
+
+task :generate_app_doc do
+ File.cp "doc/README_FOR_APP", "#{PKG_DESTINATION}/doc/README_FOR_APP"
+ system %{cd #{PKG_DESTINATION}; rake doc:app}
+end
+
+Rake::RDocTask.new { |rdoc|
+ rdoc.rdoc_dir = 'doc'
+ rdoc.title = "Railties -- Gluing the Engine to the Rails"
+ rdoc.options << '--line-numbers' << '--inline-source' << '--accessor' << 'cattr_accessor=object'
+ rdoc.options << '--charset' << 'utf-8'
+ rdoc.template = "#{ENV['template']}.rb" if ENV['template']
+ rdoc.rdoc_files.include('README', 'CHANGELOG')
+ rdoc.rdoc_files.include('lib/*.rb')
+ rdoc.rdoc_files.include('lib/rails_generator/*.rb')
+ rdoc.rdoc_files.include('lib/commands/**/*.rb')
+}
+
+# Generate GEM ----------------------------------------------------------------------------
+
+task :copy_gem_environment do
+ cp "environments/environment.rb", "#{PKG_DESTINATION}/config/environment.rb"
+ chmod 0755, dest_file
+end
+
+
+PKG_FILES = FileList[
+ '[a-zA-Z]*',
+ 'bin/**/*',
+ 'builtin/**/*',
+ 'configs/**/*',
+ 'doc/**/*',
+ 'dispatches/**/*',
+ 'environments/**/*',
+ 'helpers/**/*',
+ 'generators/**/*',
+ 'html/**/*',
+ 'lib/**/*'
+] - [ 'test' ]
+
+spec = Gem::Specification.new do |s|
+ s.platform = Gem::Platform::RUBY
+ s.name = 'rails'
+ s.version = PKG_VERSION
+ s.summary = "Web-application framework with template engine, control-flow layer, and ORM."
+ s.description = <<-EOF
+ Rails is a framework for building web-application using CGI, FCGI, mod_ruby, or WEBrick
+ on top of either MySQL, PostgreSQL, SQLite, DB2, SQL Server, or Oracle with eRuby- or Builder-based templates.
+ EOF
+
+ s.add_dependency('rake', '>= 0.7.2')
+ s.add_dependency('activesupport', '= 2.0.2' + PKG_BUILD)
+ s.add_dependency('activerecord', '= 2.0.2' + PKG_BUILD)
+ s.add_dependency('actionpack', '= 2.0.2' + PKG_BUILD)
+ s.add_dependency('actionmailer', '= 2.0.2' + PKG_BUILD)
+ s.add_dependency('activeresource', '= 2.0.2' + PKG_BUILD)
+
+ s.rdoc_options << '--exclude' << '.'
+ s.has_rdoc = false
+
+ s.files = PKG_FILES.to_a.delete_if {|f| f.include?('.svn')}
+ s.require_path = 'lib'
+ s.bindir = "bin" # Use these for applications.
+ s.executables = ["rails"]
+ s.default_executable = "rails"
+
+ s.author = "David Heinemeier Hansson"
+ s.email = "david@loudthinking.com"
+ s.homepage = "http://www.rubyonrails.org"
+ s.rubyforge_project = "rails"
+end
+
+Rake::GemPackageTask.new(spec) do |pkg|
+ pkg.gem_spec = spec
+end
+
+
+# Publishing -------------------------------------------------------
+desc "Publish the API documentation"
+task :pgem => [:gem] do
+ Rake::SshFilePublisher.new("davidhh@wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
+ `ssh davidhh@wrath.rubyonrails.org './gemupdate.sh'`
+end
+
+desc "Publish the release files to RubyForge."
+task :release => [ :package ] do
+ require 'rubyforge'
+
+ packages = %w( gem ).collect{ |ext| "pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}" }
+
+ rubyforge = RubyForge.new
+ rubyforge.login
+ rubyforge.add_release(PKG_NAME, PKG_NAME, "REL #{PKG_VERSION}", *packages)
+end
diff --git a/vendor/rails-2.0.2/railties/bin/about b/vendor/rails-2.0.2/railties/bin/about
new file mode 100644
index 000000000..cd38a32ab
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/bin/about
@@ -0,0 +1,3 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/../config/boot'
+require 'commands/about'
diff --git a/vendor/rails-2.0.2/railties/bin/console b/vendor/rails-2.0.2/railties/bin/console
new file mode 100644
index 000000000..498077ab3
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/bin/console
@@ -0,0 +1,3 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/../config/boot'
+require 'commands/console'
diff --git a/vendor/rails-2.0.2/railties/bin/destroy b/vendor/rails-2.0.2/railties/bin/destroy
new file mode 100644
index 000000000..a4df765a3
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/bin/destroy
@@ -0,0 +1,3 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/../config/boot'
+require 'commands/destroy'
diff --git a/vendor/rails-2.0.2/railties/bin/generate b/vendor/rails-2.0.2/railties/bin/generate
new file mode 100644
index 000000000..173a9f147
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/bin/generate
@@ -0,0 +1,3 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/../config/boot'
+require 'commands/generate'
diff --git a/vendor/rails-2.0.2/railties/bin/performance/benchmarker b/vendor/rails-2.0.2/railties/bin/performance/benchmarker
new file mode 100644
index 000000000..c842d35d3
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/bin/performance/benchmarker
@@ -0,0 +1,3 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/../../config/boot'
+require 'commands/performance/benchmarker'
diff --git a/vendor/rails-2.0.2/railties/bin/performance/profiler b/vendor/rails-2.0.2/railties/bin/performance/profiler
new file mode 100644
index 000000000..d855ac8b1
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/bin/performance/profiler
@@ -0,0 +1,3 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/../../config/boot'
+require 'commands/performance/profiler'
diff --git a/vendor/rails-2.0.2/railties/bin/performance/request b/vendor/rails-2.0.2/railties/bin/performance/request
new file mode 100644
index 000000000..ae3f38c74
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/bin/performance/request
@@ -0,0 +1,3 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/../../config/boot'
+require 'commands/performance/request'
diff --git a/vendor/rails-2.0.2/railties/bin/plugin b/vendor/rails-2.0.2/railties/bin/plugin
new file mode 100644
index 000000000..87cd2070f
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/bin/plugin
@@ -0,0 +1,3 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/../config/boot'
+require 'commands/plugin'
diff --git a/vendor/rails-2.0.2/railties/bin/process/inspector b/vendor/rails-2.0.2/railties/bin/process/inspector
new file mode 100644
index 000000000..bf25ad86d
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/bin/process/inspector
@@ -0,0 +1,3 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/../../config/boot'
+require 'commands/process/inspector'
diff --git a/vendor/rails-2.0.2/railties/bin/process/reaper b/vendor/rails-2.0.2/railties/bin/process/reaper
new file mode 100644
index 000000000..c77f04535
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/bin/process/reaper
@@ -0,0 +1,3 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/../../config/boot'
+require 'commands/process/reaper'
diff --git a/vendor/rails-2.0.2/railties/bin/process/spawner b/vendor/rails-2.0.2/railties/bin/process/spawner
new file mode 100644
index 000000000..7118f3983
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/bin/process/spawner
@@ -0,0 +1,3 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/../../config/boot'
+require 'commands/process/spawner'
diff --git a/vendor/rails-2.0.2/railties/bin/rails b/vendor/rails-2.0.2/railties/bin/rails
new file mode 100755
index 000000000..ae0cc8adc
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/bin/rails
@@ -0,0 +1,19 @@
+require File.dirname(__FILE__) + '/../lib/ruby_version_check'
+Signal.trap("INT") { puts; exit }
+
+require File.dirname(__FILE__) + '/../lib/rails/version'
+if %w(--version -v).include? ARGV.first
+ puts "Rails #{Rails::VERSION::STRING}"
+ exit(0)
+end
+
+freeze = ARGV.any? { |option| %w(--freeze -f).include?(option) }
+app_path = ARGV.first
+
+require File.dirname(__FILE__) + '/../lib/rails_generator'
+
+require 'rails_generator/scripts/generate'
+Rails::Generator::Base.use_application_sources!
+Rails::Generator::Scripts::Generate.new.run(ARGV, :generator => 'app')
+
+Dir.chdir(app_path) { `rake rails:freeze:gems`; puts "froze" } if freeze \ No newline at end of file
diff --git a/vendor/rails-2.0.2/railties/bin/runner b/vendor/rails-2.0.2/railties/bin/runner
new file mode 100644
index 000000000..a4a7cb25b
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/bin/runner
@@ -0,0 +1,3 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/../config/boot'
+require 'commands/runner'
diff --git a/vendor/rails-2.0.2/railties/bin/server b/vendor/rails-2.0.2/railties/bin/server
new file mode 100644
index 000000000..3c67f39b6
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/bin/server
@@ -0,0 +1,3 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/../config/boot'
+require 'commands/server'
diff --git a/vendor/rails-2.0.2/railties/builtin/rails_info/rails/info.rb b/vendor/rails-2.0.2/railties/builtin/rails_info/rails/info.rb
new file mode 100644
index 000000000..b73cc1340
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/builtin/rails_info/rails/info.rb
@@ -0,0 +1,123 @@
+module Rails
+ module Info
+ mattr_accessor :properties
+ class << (@@properties = [])
+ def names
+ map {|(name, )| name}
+ end
+
+ def value_for(property_name)
+ find {|(name, )| name == property_name}.last rescue nil
+ end
+ end
+
+ class << self #:nodoc:
+ def property(name, value = nil)
+ value ||= yield
+ properties << [name, value] if value
+ rescue Exception
+ end
+
+ def components
+ %w( active_record action_pack active_resource action_mailer active_support )
+ end
+
+ def component_version(component)
+ require "#{component}/version"
+ "#{component.classify}::VERSION::STRING".constantize
+ end
+
+ def edge_rails_revision(info = svn_info)
+ info[/^Revision: (\d+)/, 1] || freeze_edge_version
+ end
+
+ def freeze_edge_version
+ if File.exist?(rails_vendor_root)
+ begin
+ Dir[File.join(rails_vendor_root, 'REVISION_*')].first.scan(/_(\d+)$/).first.first
+ rescue
+ Dir[File.join(rails_vendor_root, 'TAG_*')].first.scan(/_(.+)$/).first.first rescue 'unknown'
+ end
+ end
+ end
+
+ def to_s
+ column_width = properties.names.map {|name| name.length}.max
+ ["About your application's environment", *properties.map do |property|
+ "%-#{column_width}s %s" % property
+ end] * "\n"
+ end
+
+ alias inspect to_s
+
+ def to_html
+ returning table = '<table>' do
+ properties.each do |(name, value)|
+ table << %(<tr><td class="name">#{CGI.escapeHTML(name.to_s)}</td>)
+ table << %(<td class="value">#{CGI.escapeHTML(value.to_s)}</td></tr>)
+ end
+ table << '</table>'
+ end
+ end
+
+ protected
+ def rails_vendor_root
+ @rails_vendor_root ||= "#{RAILS_ROOT}/vendor/rails"
+ end
+
+ def svn_info
+ env_lang, ENV['LC_ALL'] = ENV['LC_ALL'], 'C'
+ Dir.chdir(rails_vendor_root) do
+ silence_stderr { `svn info` }
+ end
+ ensure
+ ENV['LC_ALL'] = env_lang
+ end
+ end
+
+ # The Ruby version and platform, e.g. "1.8.2 (powerpc-darwin8.2.0)".
+ property 'Ruby version', "#{RUBY_VERSION} (#{RUBY_PLATFORM})"
+
+ # The RubyGems version, if it's installed.
+ property 'RubyGems version' do
+ Gem::RubyGemsVersion
+ end
+
+ # The Rails version.
+ property 'Rails version' do
+ Rails::VERSION::STRING
+ end
+
+ # Versions of each Rails component (Active Record, Action Pack,
+ # Active Resource, Action Mailer, and Active Support).
+ components.each do |component|
+ property "#{component.titlecase} version" do
+ component_version(component)
+ end
+ end
+
+ # The Rails SVN revision, if it's checked out into vendor/rails.
+ property 'Edge Rails revision' do
+ edge_rails_revision
+ end
+
+ # The application's location on the filesystem.
+ property 'Application root' do
+ File.expand_path(RAILS_ROOT)
+ end
+
+ # The current Rails environment (development, test, or production).
+ property 'Environment' do
+ RAILS_ENV
+ end
+
+ # The name of the database adapter for the current environment.
+ property 'Database adapter' do
+ ActiveRecord::Base.configurations[RAILS_ENV]['adapter']
+ end
+
+ property 'Database schema version' do
+ ActiveRecord::Migrator.current_version rescue nil
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/builtin/rails_info/rails/info_controller.rb b/vendor/rails-2.0.2/railties/builtin/rails_info/rails/info_controller.rb
new file mode 100644
index 000000000..39f8b1f12
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/builtin/rails_info/rails/info_controller.rb
@@ -0,0 +1,9 @@
+class Rails::InfoController < ActionController::Base
+ def properties
+ if local_request?
+ render :inline => Rails::Info.to_html
+ else
+ render :text => '<p>For security purposes, this information is only available to local requests.</p>', :status => 500
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/builtin/rails_info/rails/info_helper.rb b/vendor/rails-2.0.2/railties/builtin/rails_info/rails/info_helper.rb
new file mode 100644
index 000000000..e5605a8d9
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/builtin/rails_info/rails/info_helper.rb
@@ -0,0 +1,2 @@
+module Rails::InfoHelper
+end
diff --git a/vendor/rails-2.0.2/railties/builtin/rails_info/rails_info_controller.rb b/vendor/rails-2.0.2/railties/builtin/rails_info/rails_info_controller.rb
new file mode 100644
index 000000000..2009eb3a9
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/builtin/rails_info/rails_info_controller.rb
@@ -0,0 +1,2 @@
+# Alias to ensure old public.html still works.
+RailsInfoController = Rails::InfoController
diff --git a/vendor/rails-2.0.2/railties/configs/apache.conf b/vendor/rails-2.0.2/railties/configs/apache.conf
new file mode 100755
index 000000000..d9d211c05
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/configs/apache.conf
@@ -0,0 +1,40 @@
+# General Apache options
+AddHandler fastcgi-script .fcgi
+AddHandler cgi-script .cgi
+Options +FollowSymLinks +ExecCGI
+
+# If you don't want Rails to look in certain directories,
+# use the following rewrite rules so that Apache won't rewrite certain requests
+#
+# Example:
+# RewriteCond %{REQUEST_URI} ^/notrails.*
+# RewriteRule .* - [L]
+
+# Redirect all requests not available on the filesystem to Rails
+# By default the cgi dispatcher is used which is very slow
+#
+# For better performance replace the dispatcher with the fastcgi one
+#
+# Example:
+# RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
+RewriteEngine On
+
+# If your Rails application is accessed via an Alias directive,
+# then you MUST also set the RewriteBase in this htaccess file.
+#
+# Example:
+# Alias /myrailsapp /path/to/myrailsapp/public
+# RewriteBase /myrailsapp
+
+RewriteRule ^$ index.html [QSA]
+RewriteRule ^([^.]+)$ $1.html [QSA]
+RewriteCond %{REQUEST_FILENAME} !-f
+RewriteRule ^(.*)$ dispatch.cgi [QSA,L]
+
+# In case Rails experiences terminal errors
+# Instead of displaying this message you can supply a file here which will be rendered instead
+#
+# Example:
+# ErrorDocument 500 /500.html
+
+ErrorDocument 500 "<h2>Application error</h2>Rails application failed to start properly"
diff --git a/vendor/rails-2.0.2/railties/configs/databases/frontbase.yml b/vendor/rails-2.0.2/railties/configs/databases/frontbase.yml
new file mode 100644
index 000000000..2eed3133a
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/configs/databases/frontbase.yml
@@ -0,0 +1,28 @@
+# FrontBase versions 4.x
+#
+# Get the bindings:
+# gem install ruby-frontbase
+
+development:
+ adapter: frontbase
+ host: localhost
+ database: <%= app_name %>_development
+ username: <%= app_name %>
+ password: ''
+
+# 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:
+ adapter: frontbase
+ host: localhost
+ database: <%= app_name %>_test
+ username: <%= app_name %>
+ password: ''
+
+production:
+ adapter: frontbase
+ host: localhost
+ database: <%= app_name %>_production
+ username: <%= app_name %>
+ password: ''
diff --git a/vendor/rails-2.0.2/railties/configs/databases/mysql.yml b/vendor/rails-2.0.2/railties/configs/databases/mysql.yml
new file mode 100644
index 000000000..c5c894c5e
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/configs/databases/mysql.yml
@@ -0,0 +1,54 @@
+# MySQL. Versions 4.1 and 5.0 are recommended.
+#
+# Install the MySQL driver:
+# gem install mysql
+# On Mac OS X:
+# sudo gem install mysql -- --with-mysql-dir=/usr/local/mysql
+# On Mac OS X Leopard:
+# sudo env ARCHFLAGS="-arch i386" gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config
+# This sets the ARCHFLAGS environment variable to your native architecture
+# On Windows:
+# gem install mysql
+# Choose the win32 build.
+# Install MySQL and put its /bin directory on your path.
+#
+# And be sure to use new-style password hashing:
+# http://dev.mysql.com/doc/refman/5.0/en/old-client.html
+development:
+ adapter: mysql
+ encoding: utf8
+ database: <%= app_name %>_development
+ username: root
+ password:
+<% if socket -%>
+ socket: <%= socket %>
+<% else -%>
+ host: localhost
+<% end -%>
+
+# 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:
+ adapter: mysql
+ encoding: utf8
+ database: <%= app_name %>_test
+ username: root
+ password:
+<% if socket -%>
+ socket: <%= socket %>
+<% else -%>
+ host: localhost
+<% end -%>
+
+production:
+ adapter: mysql
+ encoding: utf8
+ database: <%= app_name %>_production
+ username: root
+ password:
+<% if socket -%>
+ socket: <%= socket %>
+<% else -%>
+ host: localhost
+<% end -%>
diff --git a/vendor/rails-2.0.2/railties/configs/databases/oracle.yml b/vendor/rails-2.0.2/railties/configs/databases/oracle.yml
new file mode 100644
index 000000000..c86cbdbab
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/configs/databases/oracle.yml
@@ -0,0 +1,39 @@
+# Oracle/OCI 8i, 9, 10g
+#
+# Requires Ruby/OCI8:
+# http://rubyforge.org/projects/ruby-oci8/
+#
+# Specify your database using any valid connection syntax, such as a
+# tnsnames.ora service name, or a sql connect url string of the form:
+#
+# //host:[port][/service name]
+#
+# By default prefetch_rows (OCI_ATTR_PREFETCH_ROWS) is set to 100. And
+# until true bind variables are supported, cursor_sharing is set by default
+# to 'similar'. Both can be changed in the configation below; the defaults
+# are equivalent to specifying:
+#
+# prefetch_rows: 100
+# cursor_sharing: similar
+#
+
+development:
+ adapter: oracle
+ database: <%= app_name %>_development
+ username: <%= app_name %>
+ password:
+
+# 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:
+ adapter: oracle
+ database: <%= app_name %>_test
+ username: <%= app_name %>
+ password:
+
+production:
+ adapter: oracle
+ database: <%= app_name %>_production
+ username: <%= app_name %>
+ password:
diff --git a/vendor/rails-2.0.2/railties/configs/databases/postgresql.yml b/vendor/rails-2.0.2/railties/configs/databases/postgresql.yml
new file mode 100644
index 000000000..c1b911a9a
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/configs/databases/postgresql.yml
@@ -0,0 +1,48 @@
+# PostgreSQL. Versions 7.4 and 8.x are supported.
+#
+# Install the ruby-postgres driver:
+# gem install ruby-postgres
+# On Mac OS X:
+# gem install ruby-postgres -- --include=/usr/local/pgsql
+# On Windows:
+# gem install ruby-postgres
+# Choose the win32 build.
+# Install PostgreSQL and put its /bin directory on your path.
+development:
+ adapter: postgresql
+ encoding: unicode
+ database: <%= app_name %>_development
+ username: <%= app_name %>
+ password:
+
+ # Connect on a TCP socket. Omitted by default since the client uses a
+ # domain socket that doesn't need configuration. Windows does not have
+ # domain sockets, so uncomment these lines.
+ #host: localhost
+ #port: 5432
+
+ # Schema search path. The server defaults to $user,public
+ #schema_search_path: myapp,sharedapp,public
+
+ # Minimum log levels, in increasing order:
+ # debug5, debug4, debug3, debug2, debug1,
+ # log, notice, warning, error, fatal, and panic
+ # The server defaults to notice.
+ #min_messages: warning
+
+# 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:
+ adapter: postgresql
+ encoding: unicode
+ database: <%= app_name %>_test
+ username: <%= app_name %>
+ password:
+
+production:
+ adapter: postgresql
+ encoding: unicode
+ database: <%= app_name %>_production
+ username: <%= app_name %>
+ password:
diff --git a/vendor/rails-2.0.2/railties/configs/databases/sqlite2.yml b/vendor/rails-2.0.2/railties/configs/databases/sqlite2.yml
new file mode 100644
index 000000000..26d3957d7
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/configs/databases/sqlite2.yml
@@ -0,0 +1,16 @@
+# SQLite version 2.x
+# gem install sqlite-ruby
+development:
+ adapter: sqlite
+ database: db/development.sqlite2
+
+# 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:
+ adapter: sqlite
+ database: db/test.sqlite2
+
+production:
+ adapter: sqlite
+ database: db/production.sqlite2
diff --git a/vendor/rails-2.0.2/railties/configs/databases/sqlite3.yml b/vendor/rails-2.0.2/railties/configs/databases/sqlite3.yml
new file mode 100644
index 000000000..b444b03cd
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/configs/databases/sqlite3.yml
@@ -0,0 +1,19 @@
+# SQLite version 3.x
+# gem install sqlite3-ruby (not necessary on OS X Leopard)
+development:
+ adapter: sqlite3
+ database: db/development.sqlite3
+ timeout: 5000
+
+# 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:
+ adapter: sqlite3
+ database: db/test.sqlite3
+ timeout: 5000
+
+production:
+ adapter: sqlite3
+ database: db/production.sqlite3
+ timeout: 5000
diff --git a/vendor/rails-2.0.2/railties/configs/empty.log b/vendor/rails-2.0.2/railties/configs/empty.log
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/configs/empty.log
diff --git a/vendor/rails-2.0.2/railties/configs/initializers/inflections.rb b/vendor/rails-2.0.2/railties/configs/initializers/inflections.rb
new file mode 100644
index 000000000..09158b865
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/configs/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):
+# 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/vendor/rails-2.0.2/railties/configs/initializers/mime_types.rb b/vendor/rails-2.0.2/railties/configs/initializers/mime_types.rb
new file mode 100644
index 000000000..72aca7e44
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/configs/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/vendor/rails-2.0.2/railties/configs/lighttpd.conf b/vendor/rails-2.0.2/railties/configs/lighttpd.conf
new file mode 100644
index 000000000..ed68d714b
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/configs/lighttpd.conf
@@ -0,0 +1,54 @@
+# Default configuration file for the lighttpd web server
+# Start using ./script/server lighttpd
+
+server.bind = "0.0.0.0"
+server.port = 3000
+
+server.modules = ( "mod_rewrite", "mod_accesslog", "mod_fastcgi", "mod_compress", "mod_expire" )
+
+server.error-handler-404 = "/dispatch.fcgi"
+server.pid-file = CWD + "/tmp/pids/lighttpd.pid"
+server.document-root = CWD + "/public/"
+
+server.errorlog = CWD + "/log/lighttpd.error.log"
+accesslog.filename = CWD + "/log/lighttpd.access.log"
+
+url.rewrite = ( "^/$" => "index.html", "^([^.]+)$" => "$1.html" )
+
+compress.filetype = ( "text/plain", "text/html", "text/css", "text/javascript" )
+compress.cache-dir = CWD + "/tmp/cache"
+
+expire.url = ( "/favicon.ico" => "access 3 days",
+ "/images/" => "access 3 days",
+ "/stylesheets/" => "access 3 days",
+ "/javascripts/" => "access 3 days" )
+
+
+# Change *-procs to 2 if you need to use Upload Progress or other tasks that
+# *need* to execute a second request while the first is still pending.
+fastcgi.server = ( ".fcgi" => ( "localhost" => (
+ "min-procs" => 1,
+ "max-procs" => 1,
+ "socket" => CWD + "/tmp/sockets/fcgi.socket",
+ "bin-path" => CWD + "/public/dispatch.fcgi",
+ "bin-environment" => ( "RAILS_ENV" => "development" )
+) ) )
+
+mimetype.assign = (
+ ".css" => "text/css",
+ ".gif" => "image/gif",
+ ".htm" => "text/html",
+ ".html" => "text/html",
+ ".jpeg" => "image/jpeg",
+ ".jpg" => "image/jpeg",
+ ".js" => "text/javascript",
+ ".png" => "image/png",
+ ".swf" => "application/x-shockwave-flash",
+ ".txt" => "text/plain"
+)
+
+# Making sure file uploads above 64k always work when using IE or Safari
+# For more information, see http://trac.lighttpd.net/trac/ticket/360
+$HTTP["useragent"] =~ "^(.*MSIE.*)|(.*AppleWebKit.*)$" {
+ server.max-keep-alive-requests = 0
+}
diff --git a/vendor/rails-2.0.2/railties/configs/routes.rb b/vendor/rails-2.0.2/railties/configs/routes.rb
new file mode 100644
index 000000000..d94afa1b9
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/configs/routes.rb
@@ -0,0 +1,35 @@
+ActionController::Routing::Routes.draw do |map|
+ # The priority is based upon order of creation: first created -> highest priority.
+
+ # Sample of regular route:
+ # map.connect 'products/:id', :controller => 'catalog', :action => 'view'
+ # Keep in mind you can assign values other than :controller and :action
+
+ # Sample of named route:
+ # map.purchase 'products/:id/purchase', :controller => 'catalog', :action => 'purchase'
+ # This route can be invoked with purchase_url(:id => product.id)
+
+ # Sample resource route (maps HTTP verbs to controller actions automatically):
+ # map.resources :products
+
+ # Sample resource route with options:
+ # map.resources :products, :member => { :short => :get, :toggle => :post }, :collection => { :sold => :get }
+
+ # Sample resource route with sub-resources:
+ # map.resources :products, :has_many => [ :comments, :sales ], :has_one => :seller
+
+ # Sample resource route within a namespace:
+ # map.namespace :admin do |admin|
+ # # Directs /admin/products/* to Admin::ProductsController (app/controllers/admin/products_controller.rb)
+ # admin.resources :products
+ # end
+
+ # You can have the root of your site routed with map.root -- just remember to delete public/index.html.
+ # map.root :controller => "welcome"
+
+ # See how all your routes lay out with "rake routes"
+
+ # Install the default routes as the lowest priority.
+ map.connect ':controller/:action/:id'
+ map.connect ':controller/:action/:id.:format'
+end
diff --git a/vendor/rails-2.0.2/railties/dispatches/dispatch.fcgi b/vendor/rails-2.0.2/railties/dispatches/dispatch.fcgi
new file mode 100755
index 000000000..65188f380
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/dispatches/dispatch.fcgi
@@ -0,0 +1,24 @@
+#!/usr/local/bin/ruby
+#
+# You may specify the path to the FastCGI crash log (a log of unhandled
+# exceptions which forced the FastCGI instance to exit, great for debugging)
+# and the number of requests to process before running garbage collection.
+#
+# By default, the FastCGI crash log is RAILS_ROOT/log/fastcgi.crash.log
+# and the GC period is nil (turned off). A reasonable number of requests
+# could range from 10-100 depending on the memory footprint of your app.
+#
+# Example:
+# # Default log path, normal GC behavior.
+# RailsFCGIHandler.process!
+#
+# # Default log path, 50 requests between GC.
+# RailsFCGIHandler.process! nil, 50
+#
+# # Custom log path, normal GC behavior.
+# RailsFCGIHandler.process! '/var/log/myapp_fcgi_crash.log'
+#
+require File.dirname(__FILE__) + "/../config/environment"
+require 'fcgi_handler'
+
+RailsFCGIHandler.process!
diff --git a/vendor/rails-2.0.2/railties/dispatches/dispatch.rb b/vendor/rails-2.0.2/railties/dispatches/dispatch.rb
new file mode 100755
index 000000000..9b5ae760f
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/dispatches/dispatch.rb
@@ -0,0 +1,10 @@
+#!/usr/local/bin/ruby
+
+require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT)
+
+# If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like:
+# "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired
+require "dispatcher"
+
+ADDITIONAL_LOAD_PATHS.reverse.each { |dir| $:.unshift(dir) if File.directory?(dir) } if defined?(Apache::RubyRun)
+Dispatcher.dispatch \ No newline at end of file
diff --git a/vendor/rails-2.0.2/railties/dispatches/gateway.cgi b/vendor/rails-2.0.2/railties/dispatches/gateway.cgi
new file mode 100644
index 000000000..d21bf0991
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/dispatches/gateway.cgi
@@ -0,0 +1,97 @@
+#!/usr/local/bin/ruby
+
+require 'drb'
+
+# This file includes an experimental gateway CGI implementation. It will work
+# only on platforms which support both fork and sockets.
+#
+# To enable it edit public/.htaccess and replace dispatch.cgi with gateway.cgi.
+#
+# Next, create the directory log/drb_gateway and grant the apache user rw access
+# to said directory.
+#
+# On the next request to your server, the gateway tracker should start up, along
+# with a few listener processes. This setup should provide you with much better
+# speeds than dispatch.cgi.
+#
+# Keep in mind that the first request made to the server will be slow, as the
+# tracker and listeners will have to load. Also, the tracker and listeners will
+# shutdown after a period if inactivity. You can set this value below -- the
+# default is 90 seconds.
+
+TrackerSocket = File.expand_path(File.join(File.dirname(__FILE__), '../log/drb_gateway/tracker.sock'))
+DieAfter = 90 # Seconds
+Listeners = 3
+
+def message(s)
+ $stderr.puts "gateway.cgi: #{s}" if ENV && ENV["DEBUG_GATEWAY"]
+end
+
+def listener_socket(number)
+ File.expand_path(File.join(File.dirname(__FILE__), "../log/drb_gateway/listener_#{number}.sock"))
+end
+
+unless File.exists? TrackerSocket
+ message "Starting tracker and #{Listeners} listeners"
+ fork do
+ Process.setsid
+ STDIN.reopen "/dev/null"
+ STDOUT.reopen "/dev/null", "a"
+
+ root = File.expand_path(File.dirname(__FILE__) + '/..')
+
+ message "starting tracker"
+ fork do
+ ARGV.clear
+ ARGV << TrackerSocket << Listeners.to_s << DieAfter.to_s
+ load File.join(root, 'script', 'tracker')
+ end
+
+ message "starting listeners"
+ require File.join(root, 'config/environment.rb')
+ Listeners.times do |number|
+ fork do
+ ARGV.clear
+ ARGV << listener_socket(number) << DieAfter.to_s
+ load File.join(root, 'script', 'listener')
+ end
+ end
+ end
+
+ message "waiting for tracker and listener to arise..."
+ ready = false
+ 10.times do
+ sleep 0.5
+ break if (ready = File.exists?(TrackerSocket) && File.exists?(listener_socket(0)))
+ end
+
+ if ready
+ message "tracker and listener are ready"
+ else
+ message "Waited 5 seconds, listener and tracker not ready... dropping request"
+ Kernel.exit 1
+ end
+end
+
+DRb.start_service
+
+message "connecting to tracker"
+tracker = DRbObject.new_with_uri("drbunix:#{TrackerSocket}")
+
+input = $stdin.read
+$stdin.close
+
+env = ENV.inspect
+
+output = nil
+tracker.with_listener do |number|
+ message "connecting to listener #{number}"
+ socket = listener_socket(number)
+ listener = DRbObject.new_with_uri("drbunix:#{socket}")
+ output = listener.process(env, input)
+ message "listener #{number} has finished, writing output"
+end
+
+$stdout.write output
+$stdout.flush
+$stdout.close \ No newline at end of file
diff --git a/vendor/rails-2.0.2/railties/doc/README_FOR_APP b/vendor/rails-2.0.2/railties/doc/README_FOR_APP
new file mode 100644
index 000000000..fe41f5cc2
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/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/vendor/rails-2.0.2/railties/environments/boot.rb b/vendor/rails-2.0.2/railties/environments/boot.rb
new file mode 100644
index 000000000..5697cc1bc
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/environments/boot.rb
@@ -0,0 +1,109 @@
+# Don't change this file!
+# Configure your app in config/environment.rb and config/environments/*.rb
+
+RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT)
+
+module Rails
+ class << self
+ def boot!
+ unless booted?
+ preinitialize
+ pick_boot.run
+ end
+ end
+
+ def booted?
+ defined? Rails::Initializer
+ end
+
+ def pick_boot
+ (vendor_rails? ? VendorBoot : GemBoot).new
+ end
+
+ def vendor_rails?
+ File.exist?("#{RAILS_ROOT}/vendor/rails")
+ end
+
+ # FIXME : Ruby 1.9
+ def preinitialize
+ load(preinitializer_path) if File.exists?(preinitializer_path)
+ end
+
+ def preinitializer_path
+ "#{RAILS_ROOT}/config/preinitializer.rb"
+ end
+ end
+
+ class Boot
+ def run
+ load_initializer
+ Rails::Initializer.run(:set_load_path)
+ end
+ end
+
+ class VendorBoot < Boot
+ def load_initializer
+ require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer"
+ end
+ end
+
+ class GemBoot < Boot
+ def load_initializer
+ self.class.load_rubygems
+ load_rails_gem
+ require 'initializer'
+ end
+
+ def load_rails_gem
+ if version = self.class.gem_version
+ gem 'rails', version
+ else
+ gem 'rails'
+ end
+ rescue Gem::LoadError => load_error
+ $stderr.puts %(Missing the Rails #{version} gem. Please `gem install -v=#{version} rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.)
+ exit 1
+ end
+
+ class << self
+ def rubygems_version
+ Gem::RubyGemsVersion if defined? Gem::RubyGemsVersion
+ end
+
+ def gem_version
+ if defined? RAILS_GEM_VERSION
+ RAILS_GEM_VERSION
+ elsif ENV.include?('RAILS_GEM_VERSION')
+ ENV['RAILS_GEM_VERSION']
+ else
+ parse_gem_version(read_environment_rb)
+ end
+ end
+
+ def load_rubygems
+ require 'rubygems'
+
+ unless rubygems_version >= '0.9.4'
+ $stderr.puts %(Rails requires RubyGems >= 0.9.4 (you have #{rubygems_version}). Please `gem update --system` and try again.)
+ exit 1
+ end
+
+ rescue LoadError
+ $stderr.puts %(Rails requires RubyGems >= 0.9.4. Please install RubyGems and try again: http://rubygems.rubyforge.org)
+ exit 1
+ end
+
+ def parse_gem_version(text)
+ $1 if text =~ /^[^#]*RAILS_GEM_VERSION\s*=\s*["']([!~<>=]*\s*[\d.]+)["']/
+ end
+
+ private
+ def read_environment_rb
+ File.read("#{RAILS_ROOT}/config/environment.rb")
+ end
+ end
+ end
+end
+
+# All that for this:
+Rails.boot!
diff --git a/vendor/rails-2.0.2/railties/environments/development.rb b/vendor/rails-2.0.2/railties/environments/development.rb
new file mode 100644
index 000000000..09a451f9a
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/environments/development.rb
@@ -0,0 +1,18 @@
+# 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.action_controller.consider_all_requests_local = true
+config.action_view.debug_rjs = true
+config.action_controller.perform_caching = false
+config.action_view.cache_template_extensions = false
+
+# Don't care if the mailer can't send
+config.action_mailer.raise_delivery_errors = false \ No newline at end of file
diff --git a/vendor/rails-2.0.2/railties/environments/environment.rb b/vendor/rails-2.0.2/railties/environments/environment.rb
new file mode 100644
index 000000000..79306b027
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/environments/environment.rb
@@ -0,0 +1,59 @@
+# Be sure to restart your server when you modify this file
+
+# Uncomment below to force Rails into production mode when
+# you don't control web/app server and can't set it the proper way
+# ENV['RAILS_ENV'] ||= 'production'
+
+# Specifies gem version of Rails to use when vendor/rails is not present
+<%= '# ' if freeze %>RAILS_GEM_VERSION = '<%= Rails::VERSION::STRING %>' unless defined? RAILS_GEM_VERSION
+
+# Bootstrap the Rails environment, frameworks, and default configuration
+require File.join(File.dirname(__FILE__), 'boot')
+
+Rails::Initializer.run do |config|
+ # 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.
+ # See Rails::Configuration for more options.
+
+ # Skip frameworks you're not going to use (only works if using vendor/rails).
+ # To use Rails without a database, you must remove the Active Record framework
+ # config.frameworks -= [ :active_record, :active_resource, :action_mailer ]
+
+ # Only load the plugins named here, in the order given. By default, all plugins
+ # in vendor/plugins are loaded in alphabetical order.
+ # :all can be used as a placeholder for all plugins not explicitly named
+ # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
+
+ # Add additional load paths for your own custom dirs
+ # config.load_paths += %W( #{RAILS_ROOT}/extras )
+
+ # Force all environments to use the same logger level
+ # (by default production uses :info, the others :debug)
+ # config.log_level = :debug
+
+ # Your secret key for verifying cookie session data integrity.
+ # If you change this key, all old sessions 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.
+ config.action_controller.session = {
+ :session_key => '_<%= app_name %>_session',
+ :secret => '<%= app_secret %>'
+ }
+
+ # 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')
+ # config.action_controller.session_store = :active_record_store
+
+ # 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
+
+ # Activate observers that should always be running
+ # config.active_record.observers = :cacher, :garbage_collector
+
+ # Make Active Record use UTC-base instead of local time
+ # config.active_record.default_timezone = :utc
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/railties/environments/production.rb b/vendor/rails-2.0.2/railties/environments/production.rb
new file mode 100644
index 000000000..91f541c4b
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/environments/production.rb
@@ -0,0 +1,19 @@
+# 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
+
+# Use a different logger for distributed setups
+# config.logger = SyslogLogger.new
+
+# Full error reports are disabled and caching is turned on
+config.action_controller.consider_all_requests_local = false
+config.action_controller.perform_caching = true
+config.action_view.cache_template_loading = true
+
+# 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
diff --git a/vendor/rails-2.0.2/railties/environments/test.rb b/vendor/rails-2.0.2/railties/environments/test.rb
new file mode 100644
index 000000000..58850a797
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/environments/test.rb
@@ -0,0 +1,22 @@
+# 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.action_controller.consider_all_requests_local = true
+config.action_controller.perform_caching = false
+
+# Disable request forgery protection in test environment
+config.action_controller.allow_forgery_protection = false
+
+# Tell ActionMailer 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
diff --git a/vendor/rails-2.0.2/railties/fresh_rakefile b/vendor/rails-2.0.2/railties/fresh_rakefile
new file mode 100755
index 000000000..3bb0e8592
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/fresh_rakefile
@@ -0,0 +1,10 @@
+# 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.join(File.dirname(__FILE__), 'config', 'boot'))
+
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+
+require 'tasks/rails'
diff --git a/vendor/rails-2.0.2/railties/helpers/application.rb b/vendor/rails-2.0.2/railties/helpers/application.rb
new file mode 100644
index 000000000..9a79f69a4
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/helpers/application.rb
@@ -0,0 +1,10 @@
+# Filters added to this controller apply to all controllers in the application.
+# Likewise, all the methods added will be available for all controllers.
+
+class ApplicationController < ActionController::Base
+ helper :all # include all helpers, all the time
+
+ # See ActionController::RequestForgeryProtection for details
+ # Uncomment the :secret if you're not using the cookie session store
+ protect_from_forgery # :secret => '<%= app_secret %>'
+end
diff --git a/vendor/rails-2.0.2/railties/helpers/application_helper.rb b/vendor/rails-2.0.2/railties/helpers/application_helper.rb
new file mode 100644
index 000000000..22a7940eb
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/helpers/application_helper.rb
@@ -0,0 +1,3 @@
+# Methods added to this helper will be available to all templates in the application.
+module ApplicationHelper
+end
diff --git a/vendor/rails-2.0.2/railties/helpers/test_helper.rb b/vendor/rails-2.0.2/railties/helpers/test_helper.rb
new file mode 100644
index 000000000..9f1926950
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/helpers/test_helper.rb
@@ -0,0 +1,38 @@
+ENV["RAILS_ENV"] = "test"
+require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
+require 'test_help'
+
+class Test::Unit::TestCase
+ # Transactional fixtures accelerate your tests by wrapping each test method
+ # in a transaction that's rolled back on completion. This ensures that the
+ # test database remains unchanged so your fixtures don't have to be reloaded
+ # between every test method. Fewer database queries means faster tests.
+ #
+ # Read Mike Clark's excellent walkthrough at
+ # http://clarkware.com/cgi/blosxom/2005/10/24#Rails10FastTesting
+ #
+ # Every Active Record database supports transactions except MyISAM tables
+ # in MySQL. Turn off transactional fixtures in this case; however, if you
+ # don't care one way or the other, switching from MyISAM to InnoDB tables
+ # is recommended.
+ #
+ # The only drawback to using transactional fixtures is when you actually
+ # need to test transactions. Since your test is bracketed by a transaction,
+ # any transactions started in your code will be automatically rolled back.
+ self.use_transactional_fixtures = true
+
+ # Instantiated fixtures are slow, but give you @david where otherwise you
+ # would need people(:david). If you don't want to migrate your existing
+ # test cases which use the @david style and don't mind the speed hit (each
+ # instantiated fixtures translates to a database query per test method),
+ # then set this back to true.
+ self.use_instantiated_fixtures = false
+
+ # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
+ #
+ # Note: You'll currently still have to declare fixtures explicitly in integration tests
+ # -- they do not yet inherit this setting
+ fixtures :all
+
+ # Add more helper methods to be used by all tests here...
+end
diff --git a/vendor/rails-2.0.2/railties/html/404.html b/vendor/rails-2.0.2/railties/html/404.html
new file mode 100644
index 000000000..eff660b90
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/html/404.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+ <title>The page you were looking for doesn't exist (404)</title>
+ <style type="text/css">
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
+ div.dialog {
+ width: 25em;
+ padding: 0 4em;
+ margin: 4em auto 0 auto;
+ border: 1px solid #ccc;
+ border-right-color: #999;
+ border-bottom-color: #999;
+ }
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
+ </style>
+</head>
+
+<body>
+ <!-- This file lives in public/404.html -->
+ <div class="dialog">
+ <h1>The page you were looking for doesn't exist.</h1>
+ <p>You may have mistyped the address or the page may have moved.</p>
+ </div>
+</body>
+</html> \ No newline at end of file
diff --git a/vendor/rails-2.0.2/railties/html/422.html b/vendor/rails-2.0.2/railties/html/422.html
new file mode 100644
index 000000000..b54e4a3ca
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/html/422.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+ <title>The change you wanted was rejected (422)</title>
+ <style type="text/css">
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
+ div.dialog {
+ width: 25em;
+ padding: 0 4em;
+ margin: 4em auto 0 auto;
+ border: 1px solid #ccc;
+ border-right-color: #999;
+ border-bottom-color: #999;
+ }
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
+ </style>
+</head>
+
+<body>
+ <!-- This file lives in public/422.html -->
+ <div class="dialog">
+ <h1>The change you wanted was rejected.</h1>
+ <p>Maybe you tried to change something you didn't have access to.</p>
+ </div>
+</body>
+</html> \ No newline at end of file
diff --git a/vendor/rails-2.0.2/railties/html/500.html b/vendor/rails-2.0.2/railties/html/500.html
new file mode 100644
index 000000000..0e9c14f4c
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/html/500.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+ <title>We're sorry, but something went wrong (500)</title>
+ <style type="text/css">
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
+ div.dialog {
+ width: 25em;
+ padding: 0 4em;
+ margin: 4em auto 0 auto;
+ border: 1px solid #ccc;
+ border-right-color: #999;
+ border-bottom-color: #999;
+ }
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
+ </style>
+</head>
+
+<body>
+ <!-- This file lives in public/500.html -->
+ <div class="dialog">
+ <h1>We're sorry, but something went wrong.</h1>
+ <p>We've been notified about this issue and we'll take a look at it shortly.</p>
+ </div>
+</body>
+</html> \ No newline at end of file
diff --git a/vendor/rails-2.0.2/railties/html/favicon.ico b/vendor/rails-2.0.2/railties/html/favicon.ico
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/html/favicon.ico
diff --git a/vendor/rails-2.0.2/railties/html/images/rails.png b/vendor/rails-2.0.2/railties/html/images/rails.png
new file mode 100644
index 000000000..b8441f182
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/html/images/rails.png
Binary files differ
diff --git a/vendor/rails-2.0.2/railties/html/index.html b/vendor/rails-2.0.2/railties/html/index.html
new file mode 100644
index 000000000..84b7b57c9
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/html/index.html
@@ -0,0 +1,277 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
+ <title>Ruby on Rails: Welcome aboard</title>
+ <style type="text/css" media="screen">
+ body {
+ margin: 0;
+ margin-bottom: 25px;
+ padding: 0;
+ background-color: #f0f0f0;
+ font-family: "Lucida Grande", "Bitstream Vera Sans", "Verdana";
+ font-size: 13px;
+ color: #333;
+ }
+
+ h1 {
+ font-size: 28px;
+ color: #000;
+ }
+
+ a {color: #03c}
+ a:hover {
+ background-color: #03c;
+ color: white;
+ text-decoration: none;
+ }
+
+
+ #page {
+ background-color: #f0f0f0;
+ width: 750px;
+ margin: 0;
+ margin-left: auto;
+ margin-right: auto;
+ }
+
+ #content {
+ float: left;
+ background-color: white;
+ border: 3px solid #aaa;
+ border-top: none;
+ padding: 25px;
+ width: 500px;
+ }
+
+ #sidebar {
+ float: right;
+ width: 175px;
+ }
+
+ #footer {
+ clear: both;
+ }
+
+
+ #header, #about, #getting-started {
+ padding-left: 75px;
+ padding-right: 30px;
+ }
+
+
+ #header {
+ background-image: url("images/rails.png");
+ background-repeat: no-repeat;
+ background-position: top left;
+ height: 64px;
+ }
+ #header h1, #header h2 {margin: 0}
+ #header h2 {
+ color: #888;
+ font-weight: normal;
+ font-size: 16px;
+ }
+
+
+ #about h3 {
+ margin: 0;
+ margin-bottom: 10px;
+ font-size: 14px;
+ }
+
+ #about-content {
+ background-color: #ffd;
+ border: 1px solid #fc0;
+ margin-left: -11px;
+ }
+ #about-content table {
+ margin-top: 10px;
+ margin-bottom: 10px;
+ font-size: 11px;
+ border-collapse: collapse;
+ }
+ #about-content td {
+ padding: 10px;
+ padding-top: 3px;
+ padding-bottom: 3px;
+ }
+ #about-content td.name {color: #555}
+ #about-content td.value {color: #000}
+
+ #about-content.failure {
+ background-color: #fcc;
+ border: 1px solid #f00;
+ }
+ #about-content.failure p {
+ margin: 0;
+ padding: 10px;
+ }
+
+
+ #getting-started {
+ border-top: 1px solid #ccc;
+ margin-top: 25px;
+ padding-top: 15px;
+ }
+ #getting-started h1 {
+ margin: 0;
+ font-size: 20px;
+ }
+ #getting-started h2 {
+ margin: 0;
+ font-size: 14px;
+ font-weight: normal;
+ color: #333;
+ margin-bottom: 25px;
+ }
+ #getting-started ol {
+ margin-left: 0;
+ padding-left: 0;
+ }
+ #getting-started li {
+ font-size: 18px;
+ color: #888;
+ margin-bottom: 25px;
+ }
+ #getting-started li h2 {
+ margin: 0;
+ font-weight: normal;
+ font-size: 18px;
+ color: #333;
+ }
+ #getting-started li p {
+ color: #555;
+ font-size: 13px;
+ }
+
+
+ #search {
+ margin: 0;
+ padding-top: 10px;
+ padding-bottom: 10px;
+ font-size: 11px;
+ }
+ #search input {
+ font-size: 11px;
+ margin: 2px;
+ }
+ #search-text {width: 170px}
+
+
+ #sidebar ul {
+ margin-left: 0;
+ padding-left: 0;
+ }
+ #sidebar ul h3 {
+ margin-top: 25px;
+ font-size: 16px;
+ padding-bottom: 10px;
+ border-bottom: 1px solid #ccc;
+ }
+ #sidebar li {
+ list-style-type: none;
+ }
+ #sidebar ul.links li {
+ margin-bottom: 5px;
+ }
+
+ </style>
+ <script type="text/javascript" src="javascripts/prototype.js"></script>
+ <script type="text/javascript" src="javascripts/effects.js"></script>
+ <script type="text/javascript">
+ function about() {
+ if (Element.empty('about-content')) {
+ new Ajax.Updater('about-content', 'rails/info/properties', {
+ method: 'get',
+ onFailure: function() {Element.classNames('about-content').add('failure')},
+ onComplete: function() {new Effect.BlindDown('about-content', {duration: 0.25})}
+ });
+ } else {
+ new Effect[Element.visible('about-content') ?
+ 'BlindUp' : 'BlindDown']('about-content', {duration: 0.25});
+ }
+ }
+
+ window.onload = function() {
+ $('search-text').value = '';
+ $('search').onsubmit = function() {
+ $('search-text').value = 'site:rubyonrails.org ' + $F('search-text');
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <div id="page">
+ <div id="sidebar">
+ <ul id="sidebar-items">
+ <li>
+ <form id="search" action="http://www.google.com/search" method="get">
+ <input type="hidden" name="hl" value="en" />
+ <input type="text" id="search-text" name="q" value="site:rubyonrails.org " />
+ <input type="submit" value="Search" /> the Rails site
+ </form>
+ </li>
+
+ <li>
+ <h3>Join the community</h3>
+ <ul class="links">
+ <li><a href="http://www.rubyonrails.org/">Ruby on Rails</a></li>
+ <li><a href="http://weblog.rubyonrails.org/">Official weblog</a></li>
+ <li><a href="http://lists.rubyonrails.org/">Mailing lists</a></li>
+ <li><a href="http://wiki.rubyonrails.org/rails/pages/IRC">IRC channel</a></li>
+ <li><a href="http://wiki.rubyonrails.org/">Wiki</a></li>
+ <li><a href="http://dev.rubyonrails.org/">Bug tracker</a></li>
+ </ul>
+ </li>
+
+ <li>
+ <h3>Browse the documentation</h3>
+ <ul class="links">
+ <li><a href="http://api.rubyonrails.org/">Rails API</a></li>
+ <li><a href="http://stdlib.rubyonrails.org/">Ruby standard library</a></li>
+ <li><a href="http://corelib.rubyonrails.org/">Ruby core</a></li>
+ </ul>
+ </li>
+ </ul>
+ </div>
+
+ <div id="content">
+ <div id="header">
+ <h1>Welcome aboard</h1>
+ <h2>You&rsquo;re riding Ruby on Rails!</h2>
+ </div>
+
+ <div id="about">
+ <h3><a href="rails/info/properties" onclick="about(); return false">About your application&rsquo;s environment</a></h3>
+ <div id="about-content" style="display: none"></div>
+ </div>
+
+ <div id="getting-started">
+ <h1>Getting started</h1>
+ <h2>Here&rsquo;s how to get rolling:</h2>
+
+ <ol>
+ <li>
+ <h2>Create your databases and edit <tt>config/database.yml</tt></h2>
+ <p>Rails needs to know your login and password.</p>
+ </li>
+
+ <li>
+ <h2>Use <tt>script/generate</tt> to create your models and controllers</h2>
+ <p>To see all available options, run it without parameters.</p>
+ </li>
+
+ <li>
+ <h2>Set up a default route and remove or rename this file</h2>
+ <p>Routes are set up in config/routes.rb.</p>
+ </li>
+ </ol>
+ </div>
+ </div>
+
+ <div id="footer">&nbsp;</div>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/vendor/rails-2.0.2/railties/html/javascripts/application.js b/vendor/rails-2.0.2/railties/html/javascripts/application.js
new file mode 100644
index 000000000..fe4577696
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/html/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/vendor/rails-2.0.2/railties/html/javascripts/controls.js b/vendor/rails-2.0.2/railties/html/javascripts/controls.js
new file mode 100644
index 000000000..fbc4418b8
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/html/javascripts/controls.js
@@ -0,0 +1,963 @@
+// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// (c) 2005-2007 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
+// (c) 2005-2007 Jon Tirsen (http://www.tirsen.com)
+// Contributors:
+// Richard Livsey
+// Rahul Bhargava
+// Rob Wills
+//
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+// Autocompleter.Base handles all the autocompletion functionality
+// that's independent of the data source for autocompletion. This
+// includes drawing the autocompletion menu, observing keyboard
+// and mouse events, and similar.
+//
+// Specific autocompleters need to provide, at the very least,
+// a getUpdatedChoices function that will be invoked every time
+// the text inside the monitored textbox changes. This method
+// should get the text for which to provide autocompletion by
+// invoking this.getToken(), NOT by directly accessing
+// this.element.value. This is to allow incremental tokenized
+// autocompletion. Specific auto-completion logic (AJAX, etc)
+// belongs in getUpdatedChoices.
+//
+// Tokenized incremental autocompletion is enabled automatically
+// when an autocompleter is instantiated with the 'tokens' option
+// in the options parameter, e.g.:
+// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });
+// will incrementally autocomplete with a comma as the token.
+// Additionally, ',' in the above example can be replaced with
+// a token array, e.g. { tokens: [',', '\n'] } which
+// enables autocompletion on multiple tokens. This is most
+// useful when one of the tokens is \n (a newline), as it
+// allows smart autocompletion after linebreaks.
+
+if(typeof Effect == 'undefined')
+ throw("controls.js requires including script.aculo.us' effects.js library");
+
+var Autocompleter = { }
+Autocompleter.Base = Class.create({
+ baseInitialize: function(element, update, options) {
+ element = $(element)
+ this.element = element;
+ this.update = $(update);
+ this.hasFocus = false;
+ this.changed = false;
+ this.active = false;
+ this.index = 0;
+ this.entryCount = 0;
+ this.oldElementValue = this.element.value;
+
+ if(this.setOptions)
+ this.setOptions(options);
+ else
+ this.options = options || { };
+
+ this.options.paramName = this.options.paramName || this.element.name;
+ this.options.tokens = this.options.tokens || [];
+ this.options.frequency = this.options.frequency || 0.4;
+ this.options.minChars = this.options.minChars || 1;
+ this.options.onShow = this.options.onShow ||
+ function(element, update){
+ if(!update.style.position || update.style.position=='absolute') {
+ update.style.position = 'absolute';
+ Position.clone(element, update, {
+ setHeight: false,
+ offsetTop: element.offsetHeight
+ });
+ }
+ Effect.Appear(update,{duration:0.15});
+ };
+ this.options.onHide = this.options.onHide ||
+ function(element, update){ new Effect.Fade(update,{duration:0.15}) };
+
+ if(typeof(this.options.tokens) == 'string')
+ this.options.tokens = new Array(this.options.tokens);
+ // Force carriage returns as token delimiters anyway
+ if (!this.options.tokens.include('\n'))
+ this.options.tokens.push('\n');
+
+ this.observer = null;
+
+ this.element.setAttribute('autocomplete','off');
+
+ Element.hide(this.update);
+
+ Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this));
+ Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this));
+ },
+
+ show: function() {
+ if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
+ if(!this.iefix &&
+ (Prototype.Browser.IE) &&
+ (Element.getStyle(this.update, 'position')=='absolute')) {
+ new Insertion.After(this.update,
+ '<iframe id="' + this.update.id + '_iefix" '+
+ 'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
+ 'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
+ this.iefix = $(this.update.id+'_iefix');
+ }
+ if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);
+ },
+
+ fixIEOverlapping: function() {
+ Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)});
+ this.iefix.style.zIndex = 1;
+ this.update.style.zIndex = 2;
+ Element.show(this.iefix);
+ },
+
+ hide: function() {
+ this.stopIndicator();
+ if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update);
+ if(this.iefix) Element.hide(this.iefix);
+ },
+
+ startIndicator: function() {
+ if(this.options.indicator) Element.show(this.options.indicator);
+ },
+
+ stopIndicator: function() {
+ if(this.options.indicator) Element.hide(this.options.indicator);
+ },
+
+ onKeyPress: function(event) {
+ if(this.active)
+ switch(event.keyCode) {
+ case Event.KEY_TAB:
+ case Event.KEY_RETURN:
+ this.selectEntry();
+ Event.stop(event);
+ case Event.KEY_ESC:
+ this.hide();
+ this.active = false;
+ Event.stop(event);
+ return;
+ case Event.KEY_LEFT:
+ case Event.KEY_RIGHT:
+ return;
+ case Event.KEY_UP:
+ this.markPrevious();
+ this.render();
+ Event.stop(event);
+ return;
+ case Event.KEY_DOWN:
+ this.markNext();
+ this.render();
+ Event.stop(event);
+ return;
+ }
+ else
+ if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||
+ (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return;
+
+ this.changed = true;
+ this.hasFocus = true;
+
+ if(this.observer) clearTimeout(this.observer);
+ this.observer =
+ setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
+ },
+
+ activate: function() {
+ this.changed = false;
+ this.hasFocus = true;
+ this.getUpdatedChoices();
+ },
+
+ onHover: function(event) {
+ var element = Event.findElement(event, 'LI');
+ if(this.index != element.autocompleteIndex)
+ {
+ this.index = element.autocompleteIndex;
+ this.render();
+ }
+ Event.stop(event);
+ },
+
+ onClick: function(event) {
+ var element = Event.findElement(event, 'LI');
+ this.index = element.autocompleteIndex;
+ this.selectEntry();
+ this.hide();
+ },
+
+ onBlur: function(event) {
+ // needed to make click events working
+ setTimeout(this.hide.bind(this), 250);
+ this.hasFocus = false;
+ this.active = false;
+ },
+
+ render: function() {
+ if(this.entryCount > 0) {
+ for (var i = 0; i < this.entryCount; i++)
+ this.index==i ?
+ Element.addClassName(this.getEntry(i),"selected") :
+ Element.removeClassName(this.getEntry(i),"selected");
+ if(this.hasFocus) {
+ this.show();
+ this.active = true;
+ }
+ } else {
+ this.active = false;
+ this.hide();
+ }
+ },
+
+ markPrevious: function() {
+ if(this.index > 0) this.index--
+ else this.index = this.entryCount-1;
+ this.getEntry(this.index).scrollIntoView(true);
+ },
+
+ markNext: function() {
+ if(this.index < this.entryCount-1) this.index++
+ else this.index = 0;
+ this.getEntry(this.index).scrollIntoView(false);
+ },
+
+ getEntry: function(index) {
+ return this.update.firstChild.childNodes[index];
+ },
+
+ getCurrentEntry: function() {
+ return this.getEntry(this.index);
+ },
+
+ selectEntry: function() {
+ this.active = false;
+ this.updateElement(this.getCurrentEntry());
+ },
+
+ updateElement: function(selectedElement) {
+ if (this.options.updateElement) {
+ this.options.updateElement(selectedElement);
+ return;
+ }
+ var value = '';
+ if (this.options.select) {
+ var nodes = $(selectedElement).select('.' + this.options.select) || [];
+ if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
+ } else
+ value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
+
+ var bounds = this.getTokenBounds();
+ if (bounds[0] != -1) {
+ var newValue = this.element.value.substr(0, bounds[0]);
+ var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/);
+ if (whitespace)
+ newValue += whitespace[0];
+ this.element.value = newValue + value + this.element.value.substr(bounds[1]);
+ } else {
+ this.element.value = value;
+ }
+ this.oldElementValue = this.element.value;
+ this.element.focus();
+
+ if (this.options.afterUpdateElement)
+ this.options.afterUpdateElement(this.element, selectedElement);
+ },
+
+ updateChoices: function(choices) {
+ if(!this.changed && this.hasFocus) {
+ this.update.innerHTML = choices;
+ Element.cleanWhitespace(this.update);
+ Element.cleanWhitespace(this.update.down());
+
+ if(this.update.firstChild && this.update.down().childNodes) {
+ this.entryCount =
+ this.update.down().childNodes.length;
+ for (var i = 0; i < this.entryCount; i++) {
+ var entry = this.getEntry(i);
+ entry.autocompleteIndex = i;
+ this.addObservers(entry);
+ }
+ } else {
+ this.entryCount = 0;
+ }
+
+ this.stopIndicator();
+ this.index = 0;
+
+ if(this.entryCount==1 && this.options.autoSelect) {
+ this.selectEntry();
+ this.hide();
+ } else {
+ this.render();
+ }
+ }
+ },
+
+ addObservers: function(element) {
+ Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
+ Event.observe(element, "click", this.onClick.bindAsEventListener(this));
+ },
+
+ onObserverEvent: function() {
+ this.changed = false;
+ this.tokenBounds = null;
+ if(this.getToken().length>=this.options.minChars) {
+ this.getUpdatedChoices();
+ } else {
+ this.active = false;
+ this.hide();
+ }
+ this.oldElementValue = this.element.value;
+ },
+
+ getToken: function() {
+ var bounds = this.getTokenBounds();
+ return this.element.value.substring(bounds[0], bounds[1]).strip();
+ },
+
+ getTokenBounds: function() {
+ if (null != this.tokenBounds) return this.tokenBounds;
+ var value = this.element.value;
+ if (value.strip().empty()) return [-1, 0];
+ var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue);
+ var offset = (diff == this.oldElementValue.length ? 1 : 0);
+ var prevTokenPos = -1, nextTokenPos = value.length;
+ var tp;
+ for (var index = 0, l = this.options.tokens.length; index < l; ++index) {
+ tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1);
+ if (tp > prevTokenPos) prevTokenPos = tp;
+ tp = value.indexOf(this.options.tokens[index], diff + offset);
+ if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp;
+ }
+ return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]);
+ }
+});
+
+Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) {
+ var boundary = Math.min(newS.length, oldS.length);
+ for (var index = 0; index < boundary; ++index)
+ if (newS[index] != oldS[index])
+ return index;
+ return boundary;
+};
+
+Ajax.Autocompleter = Class.create(Autocompleter.Base, {
+ initialize: function(element, update, url, options) {
+ this.baseInitialize(element, update, options);
+ this.options.asynchronous = true;
+ this.options.onComplete = this.onComplete.bind(this);
+ this.options.defaultParams = this.options.parameters || null;
+ this.url = url;
+ },
+
+ getUpdatedChoices: function() {
+ this.startIndicator();
+
+ var entry = encodeURIComponent(this.options.paramName) + '=' +
+ encodeURIComponent(this.getToken());
+
+ this.options.parameters = this.options.callback ?
+ this.options.callback(this.element, entry) : entry;
+
+ if(this.options.defaultParams)
+ this.options.parameters += '&' + this.options.defaultParams;
+
+ new Ajax.Request(this.url, this.options);
+ },
+
+ onComplete: function(request) {
+ this.updateChoices(request.responseText);
+ }
+});
+
+// The local array autocompleter. Used when you'd prefer to
+// inject an array of autocompletion options into the page, rather
+// than sending out Ajax queries, which can be quite slow sometimes.
+//
+// The constructor takes four parameters. The first two are, as usual,
+// the id of the monitored textbox, and id of the autocompletion menu.
+// The third is the array you want to autocomplete from, and the fourth
+// is the options block.
+//
+// Extra local autocompletion options:
+// - choices - How many autocompletion choices to offer
+//
+// - partialSearch - If false, the autocompleter will match entered
+// text only at the beginning of strings in the
+// autocomplete array. Defaults to true, which will
+// match text at the beginning of any *word* in the
+// strings in the autocomplete array. If you want to
+// search anywhere in the string, additionally set
+// the option fullSearch to true (default: off).
+//
+// - fullSsearch - Search anywhere in autocomplete array strings.
+//
+// - partialChars - How many characters to enter before triggering
+// a partial match (unlike minChars, which defines
+// how many characters are required to do any match
+// at all). Defaults to 2.
+//
+// - ignoreCase - Whether to ignore case when autocompleting.
+// Defaults to true.
+//
+// It's possible to pass in a custom function as the 'selector'
+// option, if you prefer to write your own autocompletion logic.
+// In that case, the other options above will not apply unless
+// you support them.
+
+Autocompleter.Local = Class.create(Autocompleter.Base, {
+ initialize: function(element, update, array, options) {
+ this.baseInitialize(element, update, options);
+ this.options.array = array;
+ },
+
+ getUpdatedChoices: function() {
+ this.updateChoices(this.options.selector(this));
+ },
+
+ setOptions: function(options) {
+ this.options = Object.extend({
+ choices: 10,
+ partialSearch: true,
+ partialChars: 2,
+ ignoreCase: true,
+ fullSearch: false,
+ selector: function(instance) {
+ var ret = []; // Beginning matches
+ var partial = []; // Inside matches
+ var entry = instance.getToken();
+ var count = 0;
+
+ for (var i = 0; i < instance.options.array.length &&
+ ret.length < instance.options.choices ; i++) {
+
+ var elem = instance.options.array[i];
+ var foundPos = instance.options.ignoreCase ?
+ elem.toLowerCase().indexOf(entry.toLowerCase()) :
+ elem.indexOf(entry);
+
+ while (foundPos != -1) {
+ if (foundPos == 0 && elem.length != entry.length) {
+ ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" +
+ elem.substr(entry.length) + "</li>");
+ break;
+ } else if (entry.length >= instance.options.partialChars &&
+ instance.options.partialSearch && foundPos != -1) {
+ if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) {
+ partial.push("<li>" + elem.substr(0, foundPos) + "<strong>" +
+ elem.substr(foundPos, entry.length) + "</strong>" + elem.substr(
+ foundPos + entry.length) + "</li>");
+ break;
+ }
+ }
+
+ foundPos = instance.options.ignoreCase ?
+ elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) :
+ elem.indexOf(entry, foundPos + 1);
+
+ }
+ }
+ if (partial.length)
+ ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))
+ return "<ul>" + ret.join('') + "</ul>";
+ }
+ }, options || { });
+ }
+});
+
+// AJAX in-place editor and collection editor
+// Full rewrite by Christophe Porteneuve <tdd@tddsworld.com> (April 2007).
+
+// Use this if you notice weird scrolling problems on some browsers,
+// the DOM might be a bit confused when this gets called so do this
+// waits 1 ms (with setTimeout) until it does the activation
+Field.scrollFreeActivate = function(field) {
+ setTimeout(function() {
+ Field.activate(field);
+ }, 1);
+}
+
+Ajax.InPlaceEditor = Class.create({
+ initialize: function(element, url, options) {
+ this.url = url;
+ this.element = element = $(element);
+ this.prepareOptions();
+ this._controls = { };
+ arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!!
+ Object.extend(this.options, options || { });
+ if (!this.options.formId && this.element.id) {
+ this.options.formId = this.element.id + '-inplaceeditor';
+ if ($(this.options.formId))
+ this.options.formId = '';
+ }
+ if (this.options.externalControl)
+ this.options.externalControl = $(this.options.externalControl);
+ if (!this.options.externalControl)
+ this.options.externalControlOnly = false;
+ this._originalBackground = this.element.getStyle('background-color') || 'transparent';
+ this.element.title = this.options.clickToEditText;
+ this._boundCancelHandler = this.handleFormCancellation.bind(this);
+ this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this);
+ this._boundFailureHandler = this.handleAJAXFailure.bind(this);
+ this._boundSubmitHandler = this.handleFormSubmission.bind(this);
+ this._boundWrapperHandler = this.wrapUp.bind(this);
+ this.registerListeners();
+ },
+ checkForEscapeOrReturn: function(e) {
+ if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return;
+ if (Event.KEY_ESC == e.keyCode)
+ this.handleFormCancellation(e);
+ else if (Event.KEY_RETURN == e.keyCode)
+ this.handleFormSubmission(e);
+ },
+ createControl: function(mode, handler, extraClasses) {
+ var control = this.options[mode + 'Control'];
+ var text = this.options[mode + 'Text'];
+ if ('button' == control) {
+ var btn = document.createElement('input');
+ btn.type = 'submit';
+ btn.value = text;
+ btn.className = 'editor_' + mode + '_button';
+ if ('cancel' == mode)
+ btn.onclick = this._boundCancelHandler;
+ this._form.appendChild(btn);
+ this._controls[mode] = btn;
+ } else if ('link' == control) {
+ var link = document.createElement('a');
+ link.href = '#';
+ link.appendChild(document.createTextNode(text));
+ link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler;
+ link.className = 'editor_' + mode + '_link';
+ if (extraClasses)
+ link.className += ' ' + extraClasses;
+ this._form.appendChild(link);
+ this._controls[mode] = link;
+ }
+ },
+ createEditField: function() {
+ var text = (this.options.loadTextURL ? this.options.loadingText : this.getText());
+ var fld;
+ if (1 >= this.options.rows && !/\r|\n/.test(this.getText())) {
+ fld = document.createElement('input');
+ fld.type = 'text';
+ var size = this.options.size || this.options.cols || 0;
+ if (0 < size) fld.size = size;
+ } else {
+ fld = document.createElement('textarea');
+ fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows);
+ fld.cols = this.options.cols || 40;
+ }
+ fld.name = this.options.paramName;
+ fld.value = text; // No HTML breaks conversion anymore
+ fld.className = 'editor_field';
+ if (this.options.submitOnBlur)
+ fld.onblur = this._boundSubmitHandler;
+ this._controls.editor = fld;
+ if (this.options.loadTextURL)
+ this.loadExternalText();
+ this._form.appendChild(this._controls.editor);
+ },
+ createForm: function() {
+ var ipe = this;
+ function addText(mode, condition) {
+ var text = ipe.options['text' + mode + 'Controls'];
+ if (!text || condition === false) return;
+ ipe._form.appendChild(document.createTextNode(text));
+ };
+ this._form = $(document.createElement('form'));
+ this._form.id = this.options.formId;
+ this._form.addClassName(this.options.formClassName);
+ this._form.onsubmit = this._boundSubmitHandler;
+ this.createEditField();
+ if ('textarea' == this._controls.editor.tagName.toLowerCase())
+ this._form.appendChild(document.createElement('br'));
+ if (this.options.onFormCustomization)
+ this.options.onFormCustomization(this, this._form);
+ addText('Before', this.options.okControl || this.options.cancelControl);
+ this.createControl('ok', this._boundSubmitHandler);
+ addText('Between', this.options.okControl && this.options.cancelControl);
+ this.createControl('cancel', this._boundCancelHandler, 'editor_cancel');
+ addText('After', this.options.okControl || this.options.cancelControl);
+ },
+ destroy: function() {
+ if (this._oldInnerHTML)
+ this.element.innerHTML = this._oldInnerHTML;
+ this.leaveEditMode();
+ this.unregisterListeners();
+ },
+ enterEditMode: function(e) {
+ if (this._saving || this._editing) return;
+ this._editing = true;
+ this.triggerCallback('onEnterEditMode');
+ if (this.options.externalControl)
+ this.options.externalControl.hide();
+ this.element.hide();
+ this.createForm();
+ this.element.parentNode.insertBefore(this._form, this.element);
+ if (!this.options.loadTextURL)
+ this.postProcessEditField();
+ if (e) Event.stop(e);
+ },
+ enterHover: function(e) {
+ if (this.options.hoverClassName)
+ this.element.addClassName(this.options.hoverClassName);
+ if (this._saving) return;
+ this.triggerCallback('onEnterHover');
+ },
+ getText: function() {
+ return this.element.innerHTML;
+ },
+ handleAJAXFailure: function(transport) {
+ this.triggerCallback('onFailure', transport);
+ if (this._oldInnerHTML) {
+ this.element.innerHTML = this._oldInnerHTML;
+ this._oldInnerHTML = null;
+ }
+ },
+ handleFormCancellation: function(e) {
+ this.wrapUp();
+ if (e) Event.stop(e);
+ },
+ handleFormSubmission: function(e) {
+ var form = this._form;
+ var value = $F(this._controls.editor);
+ this.prepareSubmission();
+ var params = this.options.callback(form, value) || '';
+ if (Object.isString(params))
+ params = params.toQueryParams();
+ params.editorId = this.element.id;
+ if (this.options.htmlResponse) {
+ var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions);
+ Object.extend(options, {
+ parameters: params,
+ onComplete: this._boundWrapperHandler,
+ onFailure: this._boundFailureHandler
+ });
+ new Ajax.Updater({ success: this.element }, this.url, options);
+ } else {
+ var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
+ Object.extend(options, {
+ parameters: params,
+ onComplete: this._boundWrapperHandler,
+ onFailure: this._boundFailureHandler
+ });
+ new Ajax.Request(this.url, options);
+ }
+ if (e) Event.stop(e);
+ },
+ leaveEditMode: function() {
+ this.element.removeClassName(this.options.savingClassName);
+ this.removeForm();
+ this.leaveHover();
+ this.element.style.backgroundColor = this._originalBackground;
+ this.element.show();
+ if (this.options.externalControl)
+ this.options.externalControl.show();
+ this._saving = false;
+ this._editing = false;
+ this._oldInnerHTML = null;
+ this.triggerCallback('onLeaveEditMode');
+ },
+ leaveHover: function(e) {
+ if (this.options.hoverClassName)
+ this.element.removeClassName(this.options.hoverClassName);
+ if (this._saving) return;
+ this.triggerCallback('onLeaveHover');
+ },
+ loadExternalText: function() {
+ this._form.addClassName(this.options.loadingClassName);
+ this._controls.editor.disabled = true;
+ var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
+ Object.extend(options, {
+ parameters: 'editorId=' + encodeURIComponent(this.element.id),
+ onComplete: Prototype.emptyFunction,
+ onSuccess: function(transport) {
+ this._form.removeClassName(this.options.loadingClassName);
+ var text = transport.responseText;
+ if (this.options.stripLoadedTextTags)
+ text = text.stripTags();
+ this._controls.editor.value = text;
+ this._controls.editor.disabled = false;
+ this.postProcessEditField();
+ }.bind(this),
+ onFailure: this._boundFailureHandler
+ });
+ new Ajax.Request(this.options.loadTextURL, options);
+ },
+ postProcessEditField: function() {
+ var fpc = this.options.fieldPostCreation;
+ if (fpc)
+ $(this._controls.editor)['focus' == fpc ? 'focus' : 'activate']();
+ },
+ prepareOptions: function() {
+ this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions);
+ Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks);
+ [this._extraDefaultOptions].flatten().compact().each(function(defs) {
+ Object.extend(this.options, defs);
+ }.bind(this));
+ },
+ prepareSubmission: function() {
+ this._saving = true;
+ this.removeForm();
+ this.leaveHover();
+ this.showSaving();
+ },
+ registerListeners: function() {
+ this._listeners = { };
+ var listener;
+ $H(Ajax.InPlaceEditor.Listeners).each(function(pair) {
+ listener = this[pair.value].bind(this);
+ this._listeners[pair.key] = listener;
+ if (!this.options.externalControlOnly)
+ this.element.observe(pair.key, listener);
+ if (this.options.externalControl)
+ this.options.externalControl.observe(pair.key, listener);
+ }.bind(this));
+ },
+ removeForm: function() {
+ if (!this._form) return;
+ this._form.remove();
+ this._form = null;
+ this._controls = { };
+ },
+ showSaving: function() {
+ this._oldInnerHTML = this.element.innerHTML;
+ this.element.innerHTML = this.options.savingText;
+ this.element.addClassName(this.options.savingClassName);
+ this.element.style.backgroundColor = this._originalBackground;
+ this.element.show();
+ },
+ triggerCallback: function(cbName, arg) {
+ if ('function' == typeof this.options[cbName]) {
+ this.options[cbName](this, arg);
+ }
+ },
+ unregisterListeners: function() {
+ $H(this._listeners).each(function(pair) {
+ if (!this.options.externalControlOnly)
+ this.element.stopObserving(pair.key, pair.value);
+ if (this.options.externalControl)
+ this.options.externalControl.stopObserving(pair.key, pair.value);
+ }.bind(this));
+ },
+ wrapUp: function(transport) {
+ this.leaveEditMode();
+ // Can't use triggerCallback due to backward compatibility: requires
+ // binding + direct element
+ this._boundComplete(transport, this.element);
+ }
+});
+
+Object.extend(Ajax.InPlaceEditor.prototype, {
+ dispose: Ajax.InPlaceEditor.prototype.destroy
+});
+
+Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, {
+ initialize: function($super, element, url, options) {
+ this._extraDefaultOptions = Ajax.InPlaceCollectionEditor.DefaultOptions;
+ $super(element, url, options);
+ },
+
+ createEditField: function() {
+ var list = document.createElement('select');
+ list.name = this.options.paramName;
+ list.size = 1;
+ this._controls.editor = list;
+ this._collection = this.options.collection || [];
+ if (this.options.loadCollectionURL)
+ this.loadCollection();
+ else
+ this.checkForExternalText();
+ this._form.appendChild(this._controls.editor);
+ },
+
+ loadCollection: function() {
+ this._form.addClassName(this.options.loadingClassName);
+ this.showLoadingText(this.options.loadingCollectionText);
+ var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
+ Object.extend(options, {
+ parameters: 'editorId=' + encodeURIComponent(this.element.id),
+ onComplete: Prototype.emptyFunction,
+ onSuccess: function(transport) {
+ var js = transport.responseText.strip();
+ if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check
+ throw 'Server returned an invalid collection representation.';
+ this._collection = eval(js);
+ this.checkForExternalText();
+ }.bind(this),
+ onFailure: this.onFailure
+ });
+ new Ajax.Request(this.options.loadCollectionURL, options);
+ },
+
+ showLoadingText: function(text) {
+ this._controls.editor.disabled = true;
+ var tempOption = this._controls.editor.firstChild;
+ if (!tempOption) {
+ tempOption = document.createElement('option');
+ tempOption.value = '';
+ this._controls.editor.appendChild(tempOption);
+ tempOption.selected = true;
+ }
+ tempOption.update((text || '').stripScripts().stripTags());
+ },
+
+ checkForExternalText: function() {
+ this._text = this.getText();
+ if (this.options.loadTextURL)
+ this.loadExternalText();
+ else
+ this.buildOptionList();
+ },
+
+ loadExternalText: function() {
+ this.showLoadingText(this.options.loadingText);
+ var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
+ Object.extend(options, {
+ parameters: 'editorId=' + encodeURIComponent(this.element.id),
+ onComplete: Prototype.emptyFunction,
+ onSuccess: function(transport) {
+ this._text = transport.responseText.strip();
+ this.buildOptionList();
+ }.bind(this),
+ onFailure: this.onFailure
+ });
+ new Ajax.Request(this.options.loadTextURL, options);
+ },
+
+ buildOptionList: function() {
+ this._form.removeClassName(this.options.loadingClassName);
+ this._collection = this._collection.map(function(entry) {
+ return 2 === entry.length ? entry : [entry, entry].flatten();
+ });
+ var marker = ('value' in this.options) ? this.options.value : this._text;
+ var textFound = this._collection.any(function(entry) {
+ return entry[0] == marker;
+ }.bind(this));
+ this._controls.editor.update('');
+ var option;
+ this._collection.each(function(entry, index) {
+ option = document.createElement('option');
+ option.value = entry[0];
+ option.selected = textFound ? entry[0] == marker : 0 == index;
+ option.appendChild(document.createTextNode(entry[1]));
+ this._controls.editor.appendChild(option);
+ }.bind(this));
+ this._controls.editor.disabled = false;
+ Field.scrollFreeActivate(this._controls.editor);
+ }
+});
+
+//**** DEPRECATION LAYER FOR InPlace[Collection]Editor! ****
+//**** This only exists for a while, in order to let ****
+//**** users adapt to the new API. Read up on the new ****
+//**** API and convert your code to it ASAP! ****
+
+Ajax.InPlaceEditor.prototype.initialize.dealWithDeprecatedOptions = function(options) {
+ if (!options) return;
+ function fallback(name, expr) {
+ if (name in options || expr === undefined) return;
+ options[name] = expr;
+ };
+ fallback('cancelControl', (options.cancelLink ? 'link' : (options.cancelButton ? 'button' :
+ options.cancelLink == options.cancelButton == false ? false : undefined)));
+ fallback('okControl', (options.okLink ? 'link' : (options.okButton ? 'button' :
+ options.okLink == options.okButton == false ? false : undefined)));
+ fallback('highlightColor', options.highlightcolor);
+ fallback('highlightEndColor', options.highlightendcolor);
+};
+
+Object.extend(Ajax.InPlaceEditor, {
+ DefaultOptions: {
+ ajaxOptions: { },
+ autoRows: 3, // Use when multi-line w/ rows == 1
+ cancelControl: 'link', // 'link'|'button'|false
+ cancelText: 'cancel',
+ clickToEditText: 'Click to edit',
+ externalControl: null, // id|elt
+ externalControlOnly: false,
+ fieldPostCreation: 'activate', // 'activate'|'focus'|false
+ formClassName: 'inplaceeditor-form',
+ formId: null, // id|elt
+ highlightColor: '#ffff99',
+ highlightEndColor: '#ffffff',
+ hoverClassName: '',
+ htmlResponse: true,
+ loadingClassName: 'inplaceeditor-loading',
+ loadingText: 'Loading...',
+ okControl: 'button', // 'link'|'button'|false
+ okText: 'ok',
+ paramName: 'value',
+ rows: 1, // If 1 and multi-line, uses autoRows
+ savingClassName: 'inplaceeditor-saving',
+ savingText: 'Saving...',
+ size: 0,
+ stripLoadedTextTags: false,
+ submitOnBlur: false,
+ textAfterControls: '',
+ textBeforeControls: '',
+ textBetweenControls: ''
+ },
+ DefaultCallbacks: {
+ callback: function(form) {
+ return Form.serialize(form);
+ },
+ onComplete: function(transport, element) {
+ // For backward compatibility, this one is bound to the IPE, and passes
+ // the element directly. It was too often customized, so we don't break it.
+ new Effect.Highlight(element, {
+ startcolor: this.options.highlightColor, keepBackgroundImage: true });
+ },
+ onEnterEditMode: null,
+ onEnterHover: function(ipe) {
+ ipe.element.style.backgroundColor = ipe.options.highlightColor;
+ if (ipe._effect)
+ ipe._effect.cancel();
+ },
+ onFailure: function(transport, ipe) {
+ alert('Error communication with the server: ' + transport.responseText.stripTags());
+ },
+ onFormCustomization: null, // Takes the IPE and its generated form, after editor, before controls.
+ onLeaveEditMode: null,
+ onLeaveHover: function(ipe) {
+ ipe._effect = new Effect.Highlight(ipe.element, {
+ startcolor: ipe.options.highlightColor, endcolor: ipe.options.highlightEndColor,
+ restorecolor: ipe._originalBackground, keepBackgroundImage: true
+ });
+ }
+ },
+ Listeners: {
+ click: 'enterEditMode',
+ keydown: 'checkForEscapeOrReturn',
+ mouseover: 'enterHover',
+ mouseout: 'leaveHover'
+ }
+});
+
+Ajax.InPlaceCollectionEditor.DefaultOptions = {
+ loadingCollectionText: 'Loading options...'
+};
+
+// Delayed observer, like Form.Element.Observer,
+// but waits for delay after last key input
+// Ideal for live-search fields
+
+Form.Element.DelayedObserver = Class.create({
+ initialize: function(element, delay, callback) {
+ this.delay = delay || 0.5;
+ this.element = $(element);
+ this.callback = callback;
+ this.timer = null;
+ this.lastValue = $F(this.element);
+ Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));
+ },
+ delayedListener: function(event) {
+ if(this.lastValue == $F(this.element)) return;
+ if(this.timer) clearTimeout(this.timer);
+ this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000);
+ this.lastValue = $F(this.element);
+ },
+ onTimerEvent: function() {
+ this.timer = null;
+ this.callback(this.element, $F(this.element));
+ }
+});
diff --git a/vendor/rails-2.0.2/railties/html/javascripts/dragdrop.js b/vendor/rails-2.0.2/railties/html/javascripts/dragdrop.js
new file mode 100644
index 000000000..ccf4a1e45
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/html/javascripts/dragdrop.js
@@ -0,0 +1,972 @@
+// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// (c) 2005-2007 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
+//
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+if(Object.isUndefined(Effect))
+ throw("dragdrop.js requires including script.aculo.us' effects.js library");
+
+var Droppables = {
+ drops: [],
+
+ remove: function(element) {
+ this.drops = this.drops.reject(function(d) { return d.element==$(element) });
+ },
+
+ add: function(element) {
+ element = $(element);
+ var options = Object.extend({
+ greedy: true,
+ hoverclass: null,
+ tree: false
+ }, arguments[1] || { });
+
+ // cache containers
+ if(options.containment) {
+ options._containers = [];
+ var containment = options.containment;
+ if(Object.isArray(containment)) {
+ containment.each( function(c) { options._containers.push($(c)) });
+ } else {
+ options._containers.push($(containment));
+ }
+ }
+
+ if(options.accept) options.accept = [options.accept].flatten();
+
+ Element.makePositioned(element); // fix IE
+ options.element = element;
+
+ this.drops.push(options);
+ },
+
+ findDeepestChild: function(drops) {
+ deepest = drops[0];
+
+ for (i = 1; i < drops.length; ++i)
+ if (Element.isParent(drops[i].element, deepest.element))
+ deepest = drops[i];
+
+ return deepest;
+ },
+
+ isContained: function(element, drop) {
+ var containmentNode;
+ if(drop.tree) {
+ containmentNode = element.treeNode;
+ } else {
+ containmentNode = element.parentNode;
+ }
+ return drop._containers.detect(function(c) { return containmentNode == c });
+ },
+
+ isAffected: function(point, element, drop) {
+ return (
+ (drop.element!=element) &&
+ ((!drop._containers) ||
+ this.isContained(element, drop)) &&
+ ((!drop.accept) ||
+ (Element.classNames(element).detect(
+ function(v) { return drop.accept.include(v) } ) )) &&
+ Position.within(drop.element, point[0], point[1]) );
+ },
+
+ deactivate: function(drop) {
+ if(drop.hoverclass)
+ Element.removeClassName(drop.element, drop.hoverclass);
+ this.last_active = null;
+ },
+
+ activate: function(drop) {
+ if(drop.hoverclass)
+ Element.addClassName(drop.element, drop.hoverclass);
+ this.last_active = drop;
+ },
+
+ show: function(point, element) {
+ if(!this.drops.length) return;
+ var drop, affected = [];
+
+ this.drops.each( function(drop) {
+ if(Droppables.isAffected(point, element, drop))
+ affected.push(drop);
+ });
+
+ if(affected.length>0)
+ drop = Droppables.findDeepestChild(affected);
+
+ if(this.last_active && this.last_active != drop) this.deactivate(this.last_active);
+ if (drop) {
+ Position.within(drop.element, point[0], point[1]);
+ if(drop.onHover)
+ drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
+
+ if (drop != this.last_active) Droppables.activate(drop);
+ }
+ },
+
+ fire: function(event, element) {
+ if(!this.last_active) return;
+ Position.prepare();
+
+ if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
+ if (this.last_active.onDrop) {
+ this.last_active.onDrop(element, this.last_active.element, event);
+ return true;
+ }
+ },
+
+ reset: function() {
+ if(this.last_active)
+ this.deactivate(this.last_active);
+ }
+}
+
+var Draggables = {
+ drags: [],
+ observers: [],
+
+ register: function(draggable) {
+ if(this.drags.length == 0) {
+ this.eventMouseUp = this.endDrag.bindAsEventListener(this);
+ this.eventMouseMove = this.updateDrag.bindAsEventListener(this);
+ this.eventKeypress = this.keyPress.bindAsEventListener(this);
+
+ Event.observe(document, "mouseup", this.eventMouseUp);
+ Event.observe(document, "mousemove", this.eventMouseMove);
+ Event.observe(document, "keypress", this.eventKeypress);
+ }
+ this.drags.push(draggable);
+ },
+
+ unregister: function(draggable) {
+ this.drags = this.drags.reject(function(d) { return d==draggable });
+ if(this.drags.length == 0) {
+ Event.stopObserving(document, "mouseup", this.eventMouseUp);
+ Event.stopObserving(document, "mousemove", this.eventMouseMove);
+ Event.stopObserving(document, "keypress", this.eventKeypress);
+ }
+ },
+
+ activate: function(draggable) {
+ if(draggable.options.delay) {
+ this._timeout = setTimeout(function() {
+ Draggables._timeout = null;
+ window.focus();
+ Draggables.activeDraggable = draggable;
+ }.bind(this), draggable.options.delay);
+ } else {
+ window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
+ this.activeDraggable = draggable;
+ }
+ },
+
+ deactivate: function() {
+ this.activeDraggable = null;
+ },
+
+ updateDrag: function(event) {
+ if(!this.activeDraggable) return;
+ var pointer = [Event.pointerX(event), Event.pointerY(event)];
+ // Mozilla-based browsers fire successive mousemove events with
+ // the same coordinates, prevent needless redrawing (moz bug?)
+ if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
+ this._lastPointer = pointer;
+
+ this.activeDraggable.updateDrag(event, pointer);
+ },
+
+ endDrag: function(event) {
+ if(this._timeout) {
+ clearTimeout(this._timeout);
+ this._timeout = null;
+ }
+ if(!this.activeDraggable) return;
+ this._lastPointer = null;
+ this.activeDraggable.endDrag(event);
+ this.activeDraggable = null;
+ },
+
+ keyPress: function(event) {
+ if(this.activeDraggable)
+ this.activeDraggable.keyPress(event);
+ },
+
+ addObserver: function(observer) {
+ this.observers.push(observer);
+ this._cacheObserverCallbacks();
+ },
+
+ removeObserver: function(element) { // element instead of observer fixes mem leaks
+ this.observers = this.observers.reject( function(o) { return o.element==element });
+ this._cacheObserverCallbacks();
+ },
+
+ notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag'
+ if(this[eventName+'Count'] > 0)
+ this.observers.each( function(o) {
+ if(o[eventName]) o[eventName](eventName, draggable, event);
+ });
+ if(draggable.options[eventName]) draggable.options[eventName](draggable, event);
+ },
+
+ _cacheObserverCallbacks: function() {
+ ['onStart','onEnd','onDrag'].each( function(eventName) {
+ Draggables[eventName+'Count'] = Draggables.observers.select(
+ function(o) { return o[eventName]; }
+ ).length;
+ });
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var Draggable = Class.create({
+ initialize: function(element) {
+ var defaults = {
+ handle: false,
+ reverteffect: function(element, top_offset, left_offset) {
+ var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
+ new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur,
+ queue: {scope:'_draggable', position:'end'}
+ });
+ },
+ endeffect: function(element) {
+ var toOpacity = Object.isNumber(element._opacity) ? element._opacity : 1.0;
+ new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity,
+ queue: {scope:'_draggable', position:'end'},
+ afterFinish: function(){
+ Draggable._dragging[element] = false
+ }
+ });
+ },
+ zindex: 1000,
+ revert: false,
+ quiet: false,
+ scroll: false,
+ scrollSensitivity: 20,
+ scrollSpeed: 15,
+ snap: false, // false, or xy or [x,y] or function(x,y){ return [x,y] }
+ delay: 0
+ };
+
+ if(!arguments[1] || Object.isUndefined(arguments[1].endeffect))
+ Object.extend(defaults, {
+ starteffect: function(element) {
+ element._opacity = Element.getOpacity(element);
+ Draggable._dragging[element] = true;
+ new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7});
+ }
+ });
+
+ var options = Object.extend(defaults, arguments[1] || { });
+
+ this.element = $(element);
+
+ if(options.handle && Object.isString(options.handle))
+ this.handle = this.element.down('.'+options.handle, 0);
+
+ if(!this.handle) this.handle = $(options.handle);
+ if(!this.handle) this.handle = this.element;
+
+ if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {
+ options.scroll = $(options.scroll);
+ this._isScrollChild = Element.childOf(this.element, options.scroll);
+ }
+
+ Element.makePositioned(this.element); // fix IE
+
+ this.options = options;
+ this.dragging = false;
+
+ this.eventMouseDown = this.initDrag.bindAsEventListener(this);
+ Event.observe(this.handle, "mousedown", this.eventMouseDown);
+
+ Draggables.register(this);
+ },
+
+ destroy: function() {
+ Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);
+ Draggables.unregister(this);
+ },
+
+ currentDelta: function() {
+ return([
+ parseInt(Element.getStyle(this.element,'left') || '0'),
+ parseInt(Element.getStyle(this.element,'top') || '0')]);
+ },
+
+ initDrag: function(event) {
+ if(!Object.isUndefined(Draggable._dragging[this.element]) &&
+ Draggable._dragging[this.element]) return;
+ if(Event.isLeftClick(event)) {
+ // abort on form elements, fixes a Firefox issue
+ var src = Event.element(event);
+ if((tag_name = src.tagName.toUpperCase()) && (
+ tag_name=='INPUT' ||
+ tag_name=='SELECT' ||
+ tag_name=='OPTION' ||
+ tag_name=='BUTTON' ||
+ tag_name=='TEXTAREA')) return;
+
+ var pointer = [Event.pointerX(event), Event.pointerY(event)];
+ var pos = Position.cumulativeOffset(this.element);
+ this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
+
+ Draggables.activate(this);
+ Event.stop(event);
+ }
+ },
+
+ startDrag: function(event) {
+ this.dragging = true;
+ if(!this.delta)
+ this.delta = this.currentDelta();
+
+ if(this.options.zindex) {
+ this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
+ this.element.style.zIndex = this.options.zindex;
+ }
+
+ if(this.options.ghosting) {
+ this._clone = this.element.cloneNode(true);
+ this.element._originallyAbsolute = (this.element.getStyle('position') == 'absolute');
+ if (!this.element._originallyAbsolute)
+ Position.absolutize(this.element);
+ this.element.parentNode.insertBefore(this._clone, this.element);
+ }
+
+ if(this.options.scroll) {
+ if (this.options.scroll == window) {
+ var where = this._getWindowScroll(this.options.scroll);
+ this.originalScrollLeft = where.left;
+ this.originalScrollTop = where.top;
+ } else {
+ this.originalScrollLeft = this.options.scroll.scrollLeft;
+ this.originalScrollTop = this.options.scroll.scrollTop;
+ }
+ }
+
+ Draggables.notify('onStart', this, event);
+
+ if(this.options.starteffect) this.options.starteffect(this.element);
+ },
+
+ updateDrag: function(event, pointer) {
+ if(!this.dragging) this.startDrag(event);
+
+ if(!this.options.quiet){
+ Position.prepare();
+ Droppables.show(pointer, this.element);
+ }
+
+ Draggables.notify('onDrag', this, event);
+
+ this.draw(pointer);
+ if(this.options.change) this.options.change(this);
+
+ if(this.options.scroll) {
+ this.stopScrolling();
+
+ var p;
+ if (this.options.scroll == window) {
+ with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }
+ } else {
+ p = Position.page(this.options.scroll);
+ p[0] += this.options.scroll.scrollLeft + Position.deltaX;
+ p[1] += this.options.scroll.scrollTop + Position.deltaY;
+ p.push(p[0]+this.options.scroll.offsetWidth);
+ p.push(p[1]+this.options.scroll.offsetHeight);
+ }
+ var speed = [0,0];
+ if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity);
+ if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity);
+ if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity);
+ if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);
+ this.startScrolling(speed);
+ }
+
+ // fix AppleWebKit rendering
+ if(Prototype.Browser.WebKit) window.scrollBy(0,0);
+
+ Event.stop(event);
+ },
+
+ finishDrag: function(event, success) {
+ this.dragging = false;
+
+ if(this.options.quiet){
+ Position.prepare();
+ var pointer = [Event.pointerX(event), Event.pointerY(event)];
+ Droppables.show(pointer, this.element);
+ }
+
+ if(this.options.ghosting) {
+ if (!this.element._originallyAbsolute)
+ Position.relativize(this.element);
+ delete this.element._originallyAbsolute;
+ Element.remove(this._clone);
+ this._clone = null;
+ }
+
+ var dropped = false;
+ if(success) {
+ dropped = Droppables.fire(event, this.element);
+ if (!dropped) dropped = false;
+ }
+ if(dropped && this.options.onDropped) this.options.onDropped(this.element);
+ Draggables.notify('onEnd', this, event);
+
+ var revert = this.options.revert;
+ if(revert && Object.isFunction(revert)) revert = revert(this.element);
+
+ var d = this.currentDelta();
+ if(revert && this.options.reverteffect) {
+ if (dropped == 0 || revert != 'failure')
+ this.options.reverteffect(this.element,
+ d[1]-this.delta[1], d[0]-this.delta[0]);
+ } else {
+ this.delta = d;
+ }
+
+ if(this.options.zindex)
+ this.element.style.zIndex = this.originalZ;
+
+ if(this.options.endeffect)
+ this.options.endeffect(this.element);
+
+ Draggables.deactivate(this);
+ Droppables.reset();
+ },
+
+ keyPress: function(event) {
+ if(event.keyCode!=Event.KEY_ESC) return;
+ this.finishDrag(event, false);
+ Event.stop(event);
+ },
+
+ endDrag: function(event) {
+ if(!this.dragging) return;
+ this.stopScrolling();
+ this.finishDrag(event, true);
+ Event.stop(event);
+ },
+
+ draw: function(point) {
+ var pos = Position.cumulativeOffset(this.element);
+ if(this.options.ghosting) {
+ var r = Position.realOffset(this.element);
+ pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
+ }
+
+ var d = this.currentDelta();
+ pos[0] -= d[0]; pos[1] -= d[1];
+
+ if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
+ pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
+ pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
+ }
+
+ var p = [0,1].map(function(i){
+ return (point[i]-pos[i]-this.offset[i])
+ }.bind(this));
+
+ if(this.options.snap) {
+ if(Object.isFunction(this.options.snap)) {
+ p = this.options.snap(p[0],p[1],this);
+ } else {
+ if(Object.isArray(this.options.snap)) {
+ p = p.map( function(v, i) {
+ return (v/this.options.snap[i]).round()*this.options.snap[i] }.bind(this))
+ } else {
+ p = p.map( function(v) {
+ return (v/this.options.snap).round()*this.options.snap }.bind(this))
+ }
+ }}
+
+ var style = this.element.style;
+ if((!this.options.constraint) || (this.options.constraint=='horizontal'))
+ style.left = p[0] + "px";
+ if((!this.options.constraint) || (this.options.constraint=='vertical'))
+ style.top = p[1] + "px";
+
+ if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
+ },
+
+ stopScrolling: function() {
+ if(this.scrollInterval) {
+ clearInterval(this.scrollInterval);
+ this.scrollInterval = null;
+ Draggables._lastScrollPointer = null;
+ }
+ },
+
+ startScrolling: function(speed) {
+ if(!(speed[0] || speed[1])) return;
+ this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];
+ this.lastScrolled = new Date();
+ this.scrollInterval = setInterval(this.scroll.bind(this), 10);
+ },
+
+ scroll: function() {
+ var current = new Date();
+ var delta = current - this.lastScrolled;
+ this.lastScrolled = current;
+ if(this.options.scroll == window) {
+ with (this._getWindowScroll(this.options.scroll)) {
+ if (this.scrollSpeed[0] || this.scrollSpeed[1]) {
+ var d = delta / 1000;
+ this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] );
+ }
+ }
+ } else {
+ this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
+ this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000;
+ }
+
+ Position.prepare();
+ Droppables.show(Draggables._lastPointer, this.element);
+ Draggables.notify('onDrag', this);
+ if (this._isScrollChild) {
+ Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);
+ Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;
+ Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;
+ if (Draggables._lastScrollPointer[0] < 0)
+ Draggables._lastScrollPointer[0] = 0;
+ if (Draggables._lastScrollPointer[1] < 0)
+ Draggables._lastScrollPointer[1] = 0;
+ this.draw(Draggables._lastScrollPointer);
+ }
+
+ if(this.options.change) this.options.change(this);
+ },
+
+ _getWindowScroll: function(w) {
+ var T, L, W, H;
+ with (w.document) {
+ if (w.document.documentElement && documentElement.scrollTop) {
+ T = documentElement.scrollTop;
+ L = documentElement.scrollLeft;
+ } else if (w.document.body) {
+ T = body.scrollTop;
+ L = body.scrollLeft;
+ }
+ if (w.innerWidth) {
+ W = w.innerWidth;
+ H = w.innerHeight;
+ } else if (w.document.documentElement && documentElement.clientWidth) {
+ W = documentElement.clientWidth;
+ H = documentElement.clientHeight;
+ } else {
+ W = body.offsetWidth;
+ H = body.offsetHeight
+ }
+ }
+ return { top: T, left: L, width: W, height: H };
+ }
+});
+
+Draggable._dragging = { };
+
+/*--------------------------------------------------------------------------*/
+
+var SortableObserver = Class.create({
+ initialize: function(element, observer) {
+ this.element = $(element);
+ this.observer = observer;
+ this.lastValue = Sortable.serialize(this.element);
+ },
+
+ onStart: function() {
+ this.lastValue = Sortable.serialize(this.element);
+ },
+
+ onEnd: function() {
+ Sortable.unmark();
+ if(this.lastValue != Sortable.serialize(this.element))
+ this.observer(this.element)
+ }
+});
+
+var Sortable = {
+ SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,
+
+ sortables: { },
+
+ _findRootElement: function(element) {
+ while (element.tagName.toUpperCase() != "BODY") {
+ if(element.id && Sortable.sortables[element.id]) return element;
+ element = element.parentNode;
+ }
+ },
+
+ options: function(element) {
+ element = Sortable._findRootElement($(element));
+ if(!element) return;
+ return Sortable.sortables[element.id];
+ },
+
+ destroy: function(element){
+ var s = Sortable.options(element);
+
+ if(s) {
+ Draggables.removeObserver(s.element);
+ s.droppables.each(function(d){ Droppables.remove(d) });
+ s.draggables.invoke('destroy');
+
+ delete Sortable.sortables[s.element.id];
+ }
+ },
+
+ create: function(element) {
+ element = $(element);
+ var options = Object.extend({
+ element: element,
+ tag: 'li', // assumes li children, override with tag: 'tagname'
+ dropOnEmpty: false,
+ tree: false,
+ treeTag: 'ul',
+ overlap: 'vertical', // one of 'vertical', 'horizontal'
+ constraint: 'vertical', // one of 'vertical', 'horizontal', false
+ containment: element, // also takes array of elements (or id's); or false
+ handle: false, // or a CSS class
+ only: false,
+ delay: 0,
+ hoverclass: null,
+ ghosting: false,
+ quiet: false,
+ scroll: false,
+ scrollSensitivity: 20,
+ scrollSpeed: 15,
+ format: this.SERIALIZE_RULE,
+
+ // these take arrays of elements or ids and can be
+ // used for better initialization performance
+ elements: false,
+ handles: false,
+
+ onChange: Prototype.emptyFunction,
+ onUpdate: Prototype.emptyFunction
+ }, arguments[1] || { });
+
+ // clear any old sortable with same element
+ this.destroy(element);
+
+ // build options for the draggables
+ var options_for_draggable = {
+ revert: true,
+ quiet: options.quiet,
+ scroll: options.scroll,
+ scrollSpeed: options.scrollSpeed,
+ scrollSensitivity: options.scrollSensitivity,
+ delay: options.delay,
+ ghosting: options.ghosting,
+ constraint: options.constraint,
+ handle: options.handle };
+
+ if(options.starteffect)
+ options_for_draggable.starteffect = options.starteffect;
+
+ if(options.reverteffect)
+ options_for_draggable.reverteffect = options.reverteffect;
+ else
+ if(options.ghosting) options_for_draggable.reverteffect = function(element) {
+ element.style.top = 0;
+ element.style.left = 0;
+ };
+
+ if(options.endeffect)
+ options_for_draggable.endeffect = options.endeffect;
+
+ if(options.zindex)
+ options_for_draggable.zindex = options.zindex;
+
+ // build options for the droppables
+ var options_for_droppable = {
+ overlap: options.overlap,
+ containment: options.containment,
+ tree: options.tree,
+ hoverclass: options.hoverclass,
+ onHover: Sortable.onHover
+ }
+
+ var options_for_tree = {
+ onHover: Sortable.onEmptyHover,
+ overlap: options.overlap,
+ containment: options.containment,
+ hoverclass: options.hoverclass
+ }
+
+ // fix for gecko engine
+ Element.cleanWhitespace(element);
+
+ options.draggables = [];
+ options.droppables = [];
+
+ // drop on empty handling
+ if(options.dropOnEmpty || options.tree) {
+ Droppables.add(element, options_for_tree);
+ options.droppables.push(element);
+ }
+
+ (options.elements || this.findElements(element, options) || []).each( function(e,i) {
+ var handle = options.handles ? $(options.handles[i]) :
+ (options.handle ? $(e).select('.' + options.handle)[0] : e);
+ options.draggables.push(
+ new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
+ Droppables.add(e, options_for_droppable);
+ if(options.tree) e.treeNode = element;
+ options.droppables.push(e);
+ });
+
+ if(options.tree) {
+ (Sortable.findTreeElements(element, options) || []).each( function(e) {
+ Droppables.add(e, options_for_tree);
+ e.treeNode = element;
+ options.droppables.push(e);
+ });
+ }
+
+ // keep reference
+ this.sortables[element.id] = options;
+
+ // for onupdate
+ Draggables.addObserver(new SortableObserver(element, options.onUpdate));
+
+ },
+
+ // return all suitable-for-sortable elements in a guaranteed order
+ findElements: function(element, options) {
+ return Element.findChildren(
+ element, options.only, options.tree ? true : false, options.tag);
+ },
+
+ findTreeElements: function(element, options) {
+ return Element.findChildren(
+ element, options.only, options.tree ? true : false, options.treeTag);
+ },
+
+ onHover: function(element, dropon, overlap) {
+ if(Element.isParent(dropon, element)) return;
+
+ if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) {
+ return;
+ } else if(overlap>0.5) {
+ Sortable.mark(dropon, 'before');
+ if(dropon.previousSibling != element) {
+ var oldParentNode = element.parentNode;
+ element.style.visibility = "hidden"; // fix gecko rendering
+ dropon.parentNode.insertBefore(element, dropon);
+ if(dropon.parentNode!=oldParentNode)
+ Sortable.options(oldParentNode).onChange(element);
+ Sortable.options(dropon.parentNode).onChange(element);
+ }
+ } else {
+ Sortable.mark(dropon, 'after');
+ var nextElement = dropon.nextSibling || null;
+ if(nextElement != element) {
+ var oldParentNode = element.parentNode;
+ element.style.visibility = "hidden"; // fix gecko rendering
+ dropon.parentNode.insertBefore(element, nextElement);
+ if(dropon.parentNode!=oldParentNode)
+ Sortable.options(oldParentNode).onChange(element);
+ Sortable.options(dropon.parentNode).onChange(element);
+ }
+ }
+ },
+
+ onEmptyHover: function(element, dropon, overlap) {
+ var oldParentNode = element.parentNode;
+ var droponOptions = Sortable.options(dropon);
+
+ if(!Element.isParent(dropon, element)) {
+ var index;
+
+ var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only});
+ var child = null;
+
+ if(children) {
+ var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);
+
+ for (index = 0; index < children.length; index += 1) {
+ if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) {
+ offset -= Element.offsetSize (children[index], droponOptions.overlap);
+ } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) {
+ child = index + 1 < children.length ? children[index + 1] : null;
+ break;
+ } else {
+ child = children[index];
+ break;
+ }
+ }
+ }
+
+ dropon.insertBefore(element, child);
+
+ Sortable.options(oldParentNode).onChange(element);
+ droponOptions.onChange(element);
+ }
+ },
+
+ unmark: function() {
+ if(Sortable._marker) Sortable._marker.hide();
+ },
+
+ mark: function(dropon, position) {
+ // mark on ghosting only
+ var sortable = Sortable.options(dropon.parentNode);
+ if(sortable && !sortable.ghosting) return;
+
+ if(!Sortable._marker) {
+ Sortable._marker =
+ ($('dropmarker') || Element.extend(document.createElement('DIV'))).
+ hide().addClassName('dropmarker').setStyle({position:'absolute'});
+ document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
+ }
+ var offsets = Position.cumulativeOffset(dropon);
+ Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'});
+
+ if(position=='after')
+ if(sortable.overlap == 'horizontal')
+ Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'});
+ else
+ Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'});
+
+ Sortable._marker.show();
+ },
+
+ _tree: function(element, options, parent) {
+ var children = Sortable.findElements(element, options) || [];
+
+ for (var i = 0; i < children.length; ++i) {
+ var match = children[i].id.match(options.format);
+
+ if (!match) continue;
+
+ var child = {
+ id: encodeURIComponent(match ? match[1] : null),
+ element: element,
+ parent: parent,
+ children: [],
+ position: parent.children.length,
+ container: $(children[i]).down(options.treeTag)
+ }
+
+ /* Get the element containing the children and recurse over it */
+ if (child.container)
+ this._tree(child.container, options, child)
+
+ parent.children.push (child);
+ }
+
+ return parent;
+ },
+
+ tree: function(element) {
+ element = $(element);
+ var sortableOptions = this.options(element);
+ var options = Object.extend({
+ tag: sortableOptions.tag,
+ treeTag: sortableOptions.treeTag,
+ only: sortableOptions.only,
+ name: element.id,
+ format: sortableOptions.format
+ }, arguments[1] || { });
+
+ var root = {
+ id: null,
+ parent: null,
+ children: [],
+ container: element,
+ position: 0
+ }
+
+ return Sortable._tree(element, options, root);
+ },
+
+ /* Construct a [i] index for a particular node */
+ _constructIndex: function(node) {
+ var index = '';
+ do {
+ if (node.id) index = '[' + node.position + ']' + index;
+ } while ((node = node.parent) != null);
+ return index;
+ },
+
+ sequence: function(element) {
+ element = $(element);
+ var options = Object.extend(this.options(element), arguments[1] || { });
+
+ return $(this.findElements(element, options) || []).map( function(item) {
+ return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
+ });
+ },
+
+ setSequence: function(element, new_sequence) {
+ element = $(element);
+ var options = Object.extend(this.options(element), arguments[2] || { });
+
+ var nodeMap = { };
+ this.findElements(element, options).each( function(n) {
+ if (n.id.match(options.format))
+ nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];
+ n.parentNode.removeChild(n);
+ });
+
+ new_sequence.each(function(ident) {
+ var n = nodeMap[ident];
+ if (n) {
+ n[1].appendChild(n[0]);
+ delete nodeMap[ident];
+ }
+ });
+ },
+
+ serialize: function(element) {
+ element = $(element);
+ var options = Object.extend(Sortable.options(element), arguments[1] || { });
+ var name = encodeURIComponent(
+ (arguments[1] && arguments[1].name) ? arguments[1].name : element.id);
+
+ if (options.tree) {
+ return Sortable.tree(element, arguments[1]).children.map( function (item) {
+ return [name + Sortable._constructIndex(item) + "[id]=" +
+ encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
+ }).flatten().join('&');
+ } else {
+ return Sortable.sequence(element, arguments[1]).map( function(item) {
+ return name + "[]=" + encodeURIComponent(item);
+ }).join('&');
+ }
+ }
+}
+
+// Returns true if child is contained within element
+Element.isParent = function(child, element) {
+ if (!child.parentNode || child == element) return false;
+ if (child.parentNode == element) return true;
+ return Element.isParent(child.parentNode, element);
+}
+
+Element.findChildren = function(element, only, recursive, tagName) {
+ if(!element.hasChildNodes()) return null;
+ tagName = tagName.toUpperCase();
+ if(only) only = [only].flatten();
+ var elements = [];
+ $A(element.childNodes).each( function(e) {
+ if(e.tagName && e.tagName.toUpperCase()==tagName &&
+ (!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
+ elements.push(e);
+ if(recursive) {
+ var grandchildren = Element.findChildren(e, only, recursive, tagName);
+ if(grandchildren) elements.push(grandchildren);
+ }
+ });
+
+ return (elements.length>0 ? elements.flatten() : []);
+}
+
+Element.offsetSize = function (element, type) {
+ return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')];
+}
diff --git a/vendor/rails-2.0.2/railties/html/javascripts/effects.js b/vendor/rails-2.0.2/railties/html/javascripts/effects.js
new file mode 100644
index 000000000..65aed2395
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/html/javascripts/effects.js
@@ -0,0 +1,1120 @@
+// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// Contributors:
+// Justin Palmer (http://encytemedia.com/)
+// Mark Pilgrim (http://diveintomark.org/)
+// Martin Bialasinki
+//
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+// converts rgb() and #xxx to #xxxxxx format,
+// returns self (or first argument) if not convertable
+String.prototype.parseColor = function() {
+ var color = '#';
+ if (this.slice(0,4) == 'rgb(') {
+ var cols = this.slice(4,this.length-1).split(',');
+ var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
+ } else {
+ if (this.slice(0,1) == '#') {
+ if (this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();
+ if (this.length==7) color = this.toLowerCase();
+ }
+ }
+ return (color.length==7 ? color : (arguments[0] || this));
+};
+
+/*--------------------------------------------------------------------------*/
+
+Element.collectTextNodes = function(element) {
+ return $A($(element).childNodes).collect( function(node) {
+ return (node.nodeType==3 ? node.nodeValue :
+ (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
+ }).flatten().join('');
+};
+
+Element.collectTextNodesIgnoreClass = function(element, className) {
+ return $A($(element).childNodes).collect( function(node) {
+ return (node.nodeType==3 ? node.nodeValue :
+ ((node.hasChildNodes() && !Element.hasClassName(node,className)) ?
+ Element.collectTextNodesIgnoreClass(node, className) : ''));
+ }).flatten().join('');
+};
+
+Element.setContentZoom = function(element, percent) {
+ element = $(element);
+ element.setStyle({fontSize: (percent/100) + 'em'});
+ if (Prototype.Browser.WebKit) window.scrollBy(0,0);
+ return element;
+};
+
+Element.getInlineOpacity = function(element){
+ return $(element).style.opacity || '';
+};
+
+Element.forceRerendering = function(element) {
+ try {
+ element = $(element);
+ var n = document.createTextNode(' ');
+ element.appendChild(n);
+ element.removeChild(n);
+ } catch(e) { }
+};
+
+/*--------------------------------------------------------------------------*/
+
+var Effect = {
+ _elementDoesNotExistError: {
+ name: 'ElementDoesNotExistError',
+ message: 'The specified DOM element does not exist, but is required for this effect to operate'
+ },
+ Transitions: {
+ linear: Prototype.K,
+ sinoidal: function(pos) {
+ return (-Math.cos(pos*Math.PI)/2) + 0.5;
+ },
+ reverse: function(pos) {
+ return 1-pos;
+ },
+ flicker: function(pos) {
+ var pos = ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
+ return pos > 1 ? 1 : pos;
+ },
+ wobble: function(pos) {
+ return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
+ },
+ pulse: function(pos, pulses) {
+ pulses = pulses || 5;
+ return (
+ ((pos % (1/pulses)) * pulses).round() == 0 ?
+ ((pos * pulses * 2) - (pos * pulses * 2).floor()) :
+ 1 - ((pos * pulses * 2) - (pos * pulses * 2).floor())
+ );
+ },
+ spring: function(pos) {
+ return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));
+ },
+ none: function(pos) {
+ return 0;
+ },
+ full: function(pos) {
+ return 1;
+ }
+ },
+ DefaultOptions: {
+ duration: 1.0, // seconds
+ fps: 100, // 100= assume 66fps max.
+ sync: false, // true for combining
+ from: 0.0,
+ to: 1.0,
+ delay: 0.0,
+ queue: 'parallel'
+ },
+ tagifyText: function(element) {
+ var tagifyStyle = 'position:relative';
+ if (Prototype.Browser.IE) tagifyStyle += ';zoom:1';
+
+ element = $(element);
+ $A(element.childNodes).each( function(child) {
+ if (child.nodeType==3) {
+ child.nodeValue.toArray().each( function(character) {
+ element.insertBefore(
+ new Element('span', {style: tagifyStyle}).update(
+ character == ' ' ? String.fromCharCode(160) : character),
+ child);
+ });
+ Element.remove(child);
+ }
+ });
+ },
+ multiple: function(element, effect) {
+ var elements;
+ if (((typeof element == 'object') ||
+ Object.isFunction(element)) &&
+ (element.length))
+ elements = element;
+ else
+ elements = $(element).childNodes;
+
+ var options = Object.extend({
+ speed: 0.1,
+ delay: 0.0
+ }, arguments[2] || { });
+ var masterDelay = options.delay;
+
+ $A(elements).each( function(element, index) {
+ new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
+ });
+ },
+ PAIRS: {
+ 'slide': ['SlideDown','SlideUp'],
+ 'blind': ['BlindDown','BlindUp'],
+ 'appear': ['Appear','Fade']
+ },
+ toggle: function(element, effect) {
+ element = $(element);
+ effect = (effect || 'appear').toLowerCase();
+ var options = Object.extend({
+ queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
+ }, arguments[2] || { });
+ Effect[element.visible() ?
+ Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
+ }
+};
+
+Effect.DefaultOptions.transition = Effect.Transitions.sinoidal;
+
+/* ------------- core effects ------------- */
+
+Effect.ScopedQueue = Class.create(Enumerable, {
+ initialize: function() {
+ this.effects = [];
+ this.interval = null;
+ },
+ _each: function(iterator) {
+ this.effects._each(iterator);
+ },
+ add: function(effect) {
+ var timestamp = new Date().getTime();
+
+ var position = Object.isString(effect.options.queue) ?
+ effect.options.queue : effect.options.queue.position;
+
+ switch(position) {
+ case 'front':
+ // move unstarted effects after this effect
+ this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
+ e.startOn += effect.finishOn;
+ e.finishOn += effect.finishOn;
+ });
+ break;
+ case 'with-last':
+ timestamp = this.effects.pluck('startOn').max() || timestamp;
+ break;
+ case 'end':
+ // start effect after last queued effect has finished
+ timestamp = this.effects.pluck('finishOn').max() || timestamp;
+ break;
+ }
+
+ effect.startOn += timestamp;
+ effect.finishOn += timestamp;
+
+ if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
+ this.effects.push(effect);
+
+ if (!this.interval)
+ this.interval = setInterval(this.loop.bind(this), 15);
+ },
+ remove: function(effect) {
+ this.effects = this.effects.reject(function(e) { return e==effect });
+ if (this.effects.length == 0) {
+ clearInterval(this.interval);
+ this.interval = null;
+ }
+ },
+ loop: function() {
+ var timePos = new Date().getTime();
+ for(var i=0, len=this.effects.length;i<len;i++)
+ this.effects[i] && this.effects[i].loop(timePos);
+ }
+});
+
+Effect.Queues = {
+ instances: $H(),
+ get: function(queueName) {
+ if (!Object.isString(queueName)) return queueName;
+
+ return this.instances.get(queueName) ||
+ this.instances.set(queueName, new Effect.ScopedQueue());
+ }
+};
+Effect.Queue = Effect.Queues.get('global');
+
+Effect.Base = Class.create({
+ position: null,
+ start: function(options) {
+ function codeForEvent(options,eventName){
+ return (
+ (options[eventName+'Internal'] ? 'this.options.'+eventName+'Internal(this);' : '') +
+ (options[eventName] ? 'this.options.'+eventName+'(this);' : '')
+ );
+ }
+ if (options && options.transition === false) options.transition = Effect.Transitions.linear;
+ this.options = Object.extend(Object.extend({ },Effect.DefaultOptions), options || { });
+ this.currentFrame = 0;
+ this.state = 'idle';
+ this.startOn = this.options.delay*1000;
+ this.finishOn = this.startOn+(this.options.duration*1000);
+ this.fromToDelta = this.options.to-this.options.from;
+ this.totalTime = this.finishOn-this.startOn;
+ this.totalFrames = this.options.fps*this.options.duration;
+
+ eval('this.render = function(pos){ '+
+ 'if (this.state=="idle"){this.state="running";'+
+ codeForEvent(this.options,'beforeSetup')+
+ (this.setup ? 'this.setup();':'')+
+ codeForEvent(this.options,'afterSetup')+
+ '};if (this.state=="running"){'+
+ 'pos=this.options.transition(pos)*'+this.fromToDelta+'+'+this.options.from+';'+
+ 'this.position=pos;'+
+ codeForEvent(this.options,'beforeUpdate')+
+ (this.update ? 'this.update(pos);':'')+
+ codeForEvent(this.options,'afterUpdate')+
+ '}}');
+
+ this.event('beforeStart');
+ if (!this.options.sync)
+ Effect.Queues.get(Object.isString(this.options.queue) ?
+ 'global' : this.options.queue.scope).add(this);
+ },
+ loop: function(timePos) {
+ if (timePos >= this.startOn) {
+ if (timePos >= this.finishOn) {
+ this.render(1.0);
+ this.cancel();
+ this.event('beforeFinish');
+ if (this.finish) this.finish();
+ this.event('afterFinish');
+ return;
+ }
+ var pos = (timePos - this.startOn) / this.totalTime,
+ frame = (pos * this.totalFrames).round();
+ if (frame > this.currentFrame) {
+ this.render(pos);
+ this.currentFrame = frame;
+ }
+ }
+ },
+ cancel: function() {
+ if (!this.options.sync)
+ Effect.Queues.get(Object.isString(this.options.queue) ?
+ 'global' : this.options.queue.scope).remove(this);
+ this.state = 'finished';
+ },
+ event: function(eventName) {
+ if (this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
+ if (this.options[eventName]) this.options[eventName](this);
+ },
+ inspect: function() {
+ var data = $H();
+ for(property in this)
+ if (!Object.isFunction(this[property])) data.set(property, this[property]);
+ return '#<Effect:' + data.inspect() + ',options:' + $H(this.options).inspect() + '>';
+ }
+});
+
+Effect.Parallel = Class.create(Effect.Base, {
+ initialize: function(effects) {
+ this.effects = effects || [];
+ this.start(arguments[1]);
+ },
+ update: function(position) {
+ this.effects.invoke('render', position);
+ },
+ finish: function(position) {
+ this.effects.each( function(effect) {
+ effect.render(1.0);
+ effect.cancel();
+ effect.event('beforeFinish');
+ if (effect.finish) effect.finish(position);
+ effect.event('afterFinish');
+ });
+ }
+});
+
+Effect.Tween = Class.create(Effect.Base, {
+ initialize: function(object, from, to) {
+ object = Object.isString(object) ? $(object) : object;
+ var args = $A(arguments), method = args.last(),
+ options = args.length == 5 ? args[3] : null;
+ this.method = Object.isFunction(method) ? method.bind(object) :
+ Object.isFunction(object[method]) ? object[method].bind(object) :
+ function(value) { object[method] = value };
+ this.start(Object.extend({ from: from, to: to }, options || { }));
+ },
+ update: function(position) {
+ this.method(position);
+ }
+});
+
+Effect.Event = Class.create(Effect.Base, {
+ initialize: function() {
+ this.start(Object.extend({ duration: 0 }, arguments[0] || { }));
+ },
+ update: Prototype.emptyFunction
+});
+
+Effect.Opacity = Class.create(Effect.Base, {
+ initialize: function(element) {
+ this.element = $(element);
+ if (!this.element) throw(Effect._elementDoesNotExistError);
+ // make this work on IE on elements without 'layout'
+ if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
+ this.element.setStyle({zoom: 1});
+ var options = Object.extend({
+ from: this.element.getOpacity() || 0.0,
+ to: 1.0
+ }, arguments[1] || { });
+ this.start(options);
+ },
+ update: function(position) {
+ this.element.setOpacity(position);
+ }
+});
+
+Effect.Move = Class.create(Effect.Base, {
+ initialize: function(element) {
+ this.element = $(element);
+ if (!this.element) throw(Effect._elementDoesNotExistError);
+ var options = Object.extend({
+ x: 0,
+ y: 0,
+ mode: 'relative'
+ }, arguments[1] || { });
+ this.start(options);
+ },
+ setup: function() {
+ this.element.makePositioned();
+ this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
+ this.originalTop = parseFloat(this.element.getStyle('top') || '0');
+ if (this.options.mode == 'absolute') {
+ this.options.x = this.options.x - this.originalLeft;
+ this.options.y = this.options.y - this.originalTop;
+ }
+ },
+ update: function(position) {
+ this.element.setStyle({
+ left: (this.options.x * position + this.originalLeft).round() + 'px',
+ top: (this.options.y * position + this.originalTop).round() + 'px'
+ });
+ }
+});
+
+// for backwards compatibility
+Effect.MoveBy = function(element, toTop, toLeft) {
+ return new Effect.Move(element,
+ Object.extend({ x: toLeft, y: toTop }, arguments[3] || { }));
+};
+
+Effect.Scale = Class.create(Effect.Base, {
+ initialize: function(element, percent) {
+ this.element = $(element);
+ if (!this.element) throw(Effect._elementDoesNotExistError);
+ var options = Object.extend({
+ scaleX: true,
+ scaleY: true,
+ scaleContent: true,
+ scaleFromCenter: false,
+ scaleMode: 'box', // 'box' or 'contents' or { } with provided values
+ scaleFrom: 100.0,
+ scaleTo: percent
+ }, arguments[2] || { });
+ this.start(options);
+ },
+ setup: function() {
+ this.restoreAfterFinish = this.options.restoreAfterFinish || false;
+ this.elementPositioning = this.element.getStyle('position');
+
+ this.originalStyle = { };
+ ['top','left','width','height','fontSize'].each( function(k) {
+ this.originalStyle[k] = this.element.style[k];
+ }.bind(this));
+
+ this.originalTop = this.element.offsetTop;
+ this.originalLeft = this.element.offsetLeft;
+
+ var fontSize = this.element.getStyle('font-size') || '100%';
+ ['em','px','%','pt'].each( function(fontSizeType) {
+ if (fontSize.indexOf(fontSizeType)>0) {
+ this.fontSize = parseFloat(fontSize);
+ this.fontSizeType = fontSizeType;
+ }
+ }.bind(this));
+
+ this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
+
+ this.dims = null;
+ if (this.options.scaleMode=='box')
+ this.dims = [this.element.offsetHeight, this.element.offsetWidth];
+ if (/^content/.test(this.options.scaleMode))
+ this.dims = [this.element.scrollHeight, this.element.scrollWidth];
+ if (!this.dims)
+ this.dims = [this.options.scaleMode.originalHeight,
+ this.options.scaleMode.originalWidth];
+ },
+ update: function(position) {
+ var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
+ if (this.options.scaleContent && this.fontSize)
+ this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
+ this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
+ },
+ finish: function(position) {
+ if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
+ },
+ setDimensions: function(height, width) {
+ var d = { };
+ if (this.options.scaleX) d.width = width.round() + 'px';
+ if (this.options.scaleY) d.height = height.round() + 'px';
+ if (this.options.scaleFromCenter) {
+ var topd = (height - this.dims[0])/2;
+ var leftd = (width - this.dims[1])/2;
+ if (this.elementPositioning == 'absolute') {
+ if (this.options.scaleY) d.top = this.originalTop-topd + 'px';
+ if (this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
+ } else {
+ if (this.options.scaleY) d.top = -topd + 'px';
+ if (this.options.scaleX) d.left = -leftd + 'px';
+ }
+ }
+ this.element.setStyle(d);
+ }
+});
+
+Effect.Highlight = Class.create(Effect.Base, {
+ initialize: function(element) {
+ this.element = $(element);
+ if (!this.element) throw(Effect._elementDoesNotExistError);
+ var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || { });
+ this.start(options);
+ },
+ setup: function() {
+ // Prevent executing on elements not in the layout flow
+ if (this.element.getStyle('display')=='none') { this.cancel(); return; }
+ // Disable background image during the effect
+ this.oldStyle = { };
+ if (!this.options.keepBackgroundImage) {
+ this.oldStyle.backgroundImage = this.element.getStyle('background-image');
+ this.element.setStyle({backgroundImage: 'none'});
+ }
+ if (!this.options.endcolor)
+ this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');
+ if (!this.options.restorecolor)
+ this.options.restorecolor = this.element.getStyle('background-color');
+ // init color calculations
+ this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
+ this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this));
+ },
+ update: function(position) {
+ this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){
+ return m+((this._base[i]+(this._delta[i]*position)).round().toColorPart()); }.bind(this)) });
+ },
+ finish: function() {
+ this.element.setStyle(Object.extend(this.oldStyle, {
+ backgroundColor: this.options.restorecolor
+ }));
+ }
+});
+
+Effect.ScrollTo = function(element) {
+ var options = arguments[1] || { },
+ scrollOffsets = document.viewport.getScrollOffsets(),
+ elementOffsets = $(element).cumulativeOffset(),
+ max = (window.height || document.body.scrollHeight) - document.viewport.getHeight();
+
+ if (options.offset) elementOffsets[1] += options.offset;
+
+ return new Effect.Tween(null,
+ scrollOffsets.top,
+ elementOffsets[1] > max ? max : elementOffsets[1],
+ options,
+ function(p){ scrollTo(scrollOffsets.left, p.round()) }
+ );
+};
+
+/* ------------- combination effects ------------- */
+
+Effect.Fade = function(element) {
+ element = $(element);
+ var oldOpacity = element.getInlineOpacity();
+ var options = Object.extend({
+ from: element.getOpacity() || 1.0,
+ to: 0.0,
+ afterFinishInternal: function(effect) {
+ if (effect.options.to!=0) return;
+ effect.element.hide().setStyle({opacity: oldOpacity});
+ }
+ }, arguments[1] || { });
+ return new Effect.Opacity(element,options);
+};
+
+Effect.Appear = function(element) {
+ element = $(element);
+ var options = Object.extend({
+ from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0),
+ to: 1.0,
+ // force Safari to render floated elements properly
+ afterFinishInternal: function(effect) {
+ effect.element.forceRerendering();
+ },
+ beforeSetup: function(effect) {
+ effect.element.setOpacity(effect.options.from).show();
+ }}, arguments[1] || { });
+ return new Effect.Opacity(element,options);
+};
+
+Effect.Puff = function(element) {
+ element = $(element);
+ var oldStyle = {
+ opacity: element.getInlineOpacity(),
+ position: element.getStyle('position'),
+ top: element.style.top,
+ left: element.style.left,
+ width: element.style.width,
+ height: element.style.height
+ };
+ return new Effect.Parallel(
+ [ new Effect.Scale(element, 200,
+ { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }),
+ new Effect.Opacity(element, { sync: true, to: 0.0 } ) ],
+ Object.extend({ duration: 1.0,
+ beforeSetupInternal: function(effect) {
+ Position.absolutize(effect.effects[0].element)
+ },
+ afterFinishInternal: function(effect) {
+ effect.effects[0].element.hide().setStyle(oldStyle); }
+ }, arguments[1] || { })
+ );
+};
+
+Effect.BlindUp = function(element) {
+ element = $(element);
+ element.makeClipping();
+ return new Effect.Scale(element, 0,
+ Object.extend({ scaleContent: false,
+ scaleX: false,
+ restoreAfterFinish: true,
+ afterFinishInternal: function(effect) {
+ effect.element.hide().undoClipping();
+ }
+ }, arguments[1] || { })
+ );
+};
+
+Effect.BlindDown = function(element) {
+ element = $(element);
+ var elementDimensions = element.getDimensions();
+ return new Effect.Scale(element, 100, Object.extend({
+ scaleContent: false,
+ scaleX: false,
+ scaleFrom: 0,
+ scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
+ restoreAfterFinish: true,
+ afterSetup: function(effect) {
+ effect.element.makeClipping().setStyle({height: '0px'}).show();
+ },
+ afterFinishInternal: function(effect) {
+ effect.element.undoClipping();
+ }
+ }, arguments[1] || { }));
+};
+
+Effect.SwitchOff = function(element) {
+ element = $(element);
+ var oldOpacity = element.getInlineOpacity();
+ return new Effect.Appear(element, Object.extend({
+ duration: 0.4,
+ from: 0,
+ transition: Effect.Transitions.flicker,
+ afterFinishInternal: function(effect) {
+ new Effect.Scale(effect.element, 1, {
+ duration: 0.3, scaleFromCenter: true,
+ scaleX: false, scaleContent: false, restoreAfterFinish: true,
+ beforeSetup: function(effect) {
+ effect.element.makePositioned().makeClipping();
+ },
+ afterFinishInternal: function(effect) {
+ effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});
+ }
+ })
+ }
+ }, arguments[1] || { }));
+};
+
+Effect.DropOut = function(element) {
+ element = $(element);
+ var oldStyle = {
+ top: element.getStyle('top'),
+ left: element.getStyle('left'),
+ opacity: element.getInlineOpacity() };
+ return new Effect.Parallel(
+ [ new Effect.Move(element, {x: 0, y: 100, sync: true }),
+ new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
+ Object.extend(
+ { duration: 0.5,
+ beforeSetup: function(effect) {
+ effect.effects[0].element.makePositioned();
+ },
+ afterFinishInternal: function(effect) {
+ effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
+ }
+ }, arguments[1] || { }));
+};
+
+Effect.Shake = function(element) {
+ element = $(element);
+ var options = Object.extend({
+ distance: 20,
+ duration: 0.5
+ }, arguments[1] || {});
+ var distance = parseFloat(options.distance);
+ var split = parseFloat(options.duration) / 10.0;
+ var oldStyle = {
+ top: element.getStyle('top'),
+ left: element.getStyle('left') };
+ return new Effect.Move(element,
+ { x: distance, y: 0, duration: split, afterFinishInternal: function(effect) {
+ new Effect.Move(effect.element,
+ { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
+ new Effect.Move(effect.element,
+ { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
+ new Effect.Move(effect.element,
+ { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
+ new Effect.Move(effect.element,
+ { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
+ new Effect.Move(effect.element,
+ { x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) {
+ effect.element.undoPositioned().setStyle(oldStyle);
+ }}) }}) }}) }}) }}) }});
+};
+
+Effect.SlideDown = function(element) {
+ element = $(element).cleanWhitespace();
+ // SlideDown need to have the content of the element wrapped in a container element with fixed height!
+ var oldInnerBottom = element.down().getStyle('bottom');
+ var elementDimensions = element.getDimensions();
+ return new Effect.Scale(element, 100, Object.extend({
+ scaleContent: false,
+ scaleX: false,
+ scaleFrom: window.opera ? 0 : 1,
+ scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
+ restoreAfterFinish: true,
+ afterSetup: function(effect) {
+ effect.element.makePositioned();
+ effect.element.down().makePositioned();
+ if (window.opera) effect.element.setStyle({top: ''});
+ effect.element.makeClipping().setStyle({height: '0px'}).show();
+ },
+ afterUpdateInternal: function(effect) {
+ effect.element.down().setStyle({bottom:
+ (effect.dims[0] - effect.element.clientHeight) + 'px' });
+ },
+ afterFinishInternal: function(effect) {
+ effect.element.undoClipping().undoPositioned();
+ effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
+ }, arguments[1] || { })
+ );
+};
+
+Effect.SlideUp = function(element) {
+ element = $(element).cleanWhitespace();
+ var oldInnerBottom = element.down().getStyle('bottom');
+ var elementDimensions = element.getDimensions();
+ return new Effect.Scale(element, window.opera ? 0 : 1,
+ Object.extend({ scaleContent: false,
+ scaleX: false,
+ scaleMode: 'box',
+ scaleFrom: 100,
+ scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
+ restoreAfterFinish: true,
+ afterSetup: function(effect) {
+ effect.element.makePositioned();
+ effect.element.down().makePositioned();
+ if (window.opera) effect.element.setStyle({top: ''});
+ effect.element.makeClipping().show();
+ },
+ afterUpdateInternal: function(effect) {
+ effect.element.down().setStyle({bottom:
+ (effect.dims[0] - effect.element.clientHeight) + 'px' });
+ },
+ afterFinishInternal: function(effect) {
+ effect.element.hide().undoClipping().undoPositioned();
+ effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom});
+ }
+ }, arguments[1] || { })
+ );
+};
+
+// Bug in opera makes the TD containing this element expand for a instance after finish
+Effect.Squish = function(element) {
+ return new Effect.Scale(element, window.opera ? 1 : 0, {
+ restoreAfterFinish: true,
+ beforeSetup: function(effect) {
+ effect.element.makeClipping();
+ },
+ afterFinishInternal: function(effect) {
+ effect.element.hide().undoClipping();
+ }
+ });
+};
+
+Effect.Grow = function(element) {
+ element = $(element);
+ var options = Object.extend({
+ direction: 'center',
+ moveTransition: Effect.Transitions.sinoidal,
+ scaleTransition: Effect.Transitions.sinoidal,
+ opacityTransition: Effect.Transitions.full
+ }, arguments[1] || { });
+ var oldStyle = {
+ top: element.style.top,
+ left: element.style.left,
+ height: element.style.height,
+ width: element.style.width,
+ opacity: element.getInlineOpacity() };
+
+ var dims = element.getDimensions();
+ var initialMoveX, initialMoveY;
+ var moveX, moveY;
+
+ switch (options.direction) {
+ case 'top-left':
+ initialMoveX = initialMoveY = moveX = moveY = 0;
+ break;
+ case 'top-right':
+ initialMoveX = dims.width;
+ initialMoveY = moveY = 0;
+ moveX = -dims.width;
+ break;
+ case 'bottom-left':
+ initialMoveX = moveX = 0;
+ initialMoveY = dims.height;
+ moveY = -dims.height;
+ break;
+ case 'bottom-right':
+ initialMoveX = dims.width;
+ initialMoveY = dims.height;
+ moveX = -dims.width;
+ moveY = -dims.height;
+ break;
+ case 'center':
+ initialMoveX = dims.width / 2;
+ initialMoveY = dims.height / 2;
+ moveX = -dims.width / 2;
+ moveY = -dims.height / 2;
+ break;
+ }
+
+ return new Effect.Move(element, {
+ x: initialMoveX,
+ y: initialMoveY,
+ duration: 0.01,
+ beforeSetup: function(effect) {
+ effect.element.hide().makeClipping().makePositioned();
+ },
+ afterFinishInternal: function(effect) {
+ new Effect.Parallel(
+ [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
+ new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
+ new Effect.Scale(effect.element, 100, {
+ scaleMode: { originalHeight: dims.height, originalWidth: dims.width },
+ sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
+ ], Object.extend({
+ beforeSetup: function(effect) {
+ effect.effects[0].element.setStyle({height: '0px'}).show();
+ },
+ afterFinishInternal: function(effect) {
+ effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle);
+ }
+ }, options)
+ )
+ }
+ });
+};
+
+Effect.Shrink = function(element) {
+ element = $(element);
+ var options = Object.extend({
+ direction: 'center',
+ moveTransition: Effect.Transitions.sinoidal,
+ scaleTransition: Effect.Transitions.sinoidal,
+ opacityTransition: Effect.Transitions.none
+ }, arguments[1] || { });
+ var oldStyle = {
+ top: element.style.top,
+ left: element.style.left,
+ height: element.style.height,
+ width: element.style.width,
+ opacity: element.getInlineOpacity() };
+
+ var dims = element.getDimensions();
+ var moveX, moveY;
+
+ switch (options.direction) {
+ case 'top-left':
+ moveX = moveY = 0;
+ break;
+ case 'top-right':
+ moveX = dims.width;
+ moveY = 0;
+ break;
+ case 'bottom-left':
+ moveX = 0;
+ moveY = dims.height;
+ break;
+ case 'bottom-right':
+ moveX = dims.width;
+ moveY = dims.height;
+ break;
+ case 'center':
+ moveX = dims.width / 2;
+ moveY = dims.height / 2;
+ break;
+ }
+
+ return new Effect.Parallel(
+ [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
+ new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
+ new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
+ ], Object.extend({
+ beforeStartInternal: function(effect) {
+ effect.effects[0].element.makePositioned().makeClipping();
+ },
+ afterFinishInternal: function(effect) {
+ effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
+ }, options)
+ );
+};
+
+Effect.Pulsate = function(element) {
+ element = $(element);
+ var options = arguments[1] || { };
+ var oldOpacity = element.getInlineOpacity();
+ var transition = options.transition || Effect.Transitions.sinoidal;
+ var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) };
+ reverser.bind(transition);
+ return new Effect.Opacity(element,
+ Object.extend(Object.extend({ duration: 2.0, from: 0,
+ afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
+ }, options), {transition: reverser}));
+};
+
+Effect.Fold = function(element) {
+ element = $(element);
+ var oldStyle = {
+ top: element.style.top,
+ left: element.style.left,
+ width: element.style.width,
+ height: element.style.height };
+ element.makeClipping();
+ return new Effect.Scale(element, 5, Object.extend({
+ scaleContent: false,
+ scaleX: false,
+ afterFinishInternal: function(effect) {
+ new Effect.Scale(element, 1, {
+ scaleContent: false,
+ scaleY: false,
+ afterFinishInternal: function(effect) {
+ effect.element.hide().undoClipping().setStyle(oldStyle);
+ } });
+ }}, arguments[1] || { }));
+};
+
+Effect.Morph = Class.create(Effect.Base, {
+ initialize: function(element) {
+ this.element = $(element);
+ if (!this.element) throw(Effect._elementDoesNotExistError);
+ var options = Object.extend({
+ style: { }
+ }, arguments[1] || { });
+
+ if (!Object.isString(options.style)) this.style = $H(options.style);
+ else {
+ if (options.style.include(':'))
+ this.style = options.style.parseStyle();
+ else {
+ this.element.addClassName(options.style);
+ this.style = $H(this.element.getStyles());
+ this.element.removeClassName(options.style);
+ var css = this.element.getStyles();
+ this.style = this.style.reject(function(style) {
+ return style.value == css[style.key];
+ });
+ options.afterFinishInternal = function(effect) {
+ effect.element.addClassName(effect.options.style);
+ effect.transforms.each(function(transform) {
+ effect.element.style[transform.style] = '';
+ });
+ }
+ }
+ }
+ this.start(options);
+ },
+
+ setup: function(){
+ function parseColor(color){
+ if (!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
+ color = color.parseColor();
+ return $R(0,2).map(function(i){
+ return parseInt( color.slice(i*2+1,i*2+3), 16 )
+ });
+ }
+ this.transforms = this.style.map(function(pair){
+ var property = pair[0], value = pair[1], unit = null;
+
+ if (value.parseColor('#zzzzzz') != '#zzzzzz') {
+ value = value.parseColor();
+ unit = 'color';
+ } else if (property == 'opacity') {
+ value = parseFloat(value);
+ if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
+ this.element.setStyle({zoom: 1});
+ } else if (Element.CSS_LENGTH.test(value)) {
+ var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/);
+ value = parseFloat(components[1]);
+ unit = (components.length == 3) ? components[2] : null;
+ }
+
+ var originalValue = this.element.getStyle(property);
+ return {
+ style: property.camelize(),
+ originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0),
+ targetValue: unit=='color' ? parseColor(value) : value,
+ unit: unit
+ };
+ }.bind(this)).reject(function(transform){
+ return (
+ (transform.originalValue == transform.targetValue) ||
+ (
+ transform.unit != 'color' &&
+ (isNaN(transform.originalValue) || isNaN(transform.targetValue))
+ )
+ )
+ });
+ },
+ update: function(position) {
+ var style = { }, transform, i = this.transforms.length;
+ while(i--)
+ style[(transform = this.transforms[i]).style] =
+ transform.unit=='color' ? '#'+
+ (Math.round(transform.originalValue[0]+
+ (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() +
+ (Math.round(transform.originalValue[1]+
+ (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() +
+ (Math.round(transform.originalValue[2]+
+ (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() :
+ (transform.originalValue +
+ (transform.targetValue - transform.originalValue) * position).toFixed(3) +
+ (transform.unit === null ? '' : transform.unit);
+ this.element.setStyle(style, true);
+ }
+});
+
+Effect.Transform = Class.create({
+ initialize: function(tracks){
+ this.tracks = [];
+ this.options = arguments[1] || { };
+ this.addTracks(tracks);
+ },
+ addTracks: function(tracks){
+ tracks.each(function(track){
+ track = $H(track);
+ var data = track.values().first();
+ this.tracks.push($H({
+ ids: track.keys().first(),
+ effect: Effect.Morph,
+ options: { style: data }
+ }));
+ }.bind(this));
+ return this;
+ },
+ play: function(){
+ return new Effect.Parallel(
+ this.tracks.map(function(track){
+ var ids = track.get('ids'), effect = track.get('effect'), options = track.get('options');
+ var elements = [$(ids) || $$(ids)].flatten();
+ return elements.map(function(e){ return new effect(e, Object.extend({ sync:true }, options)) });
+ }).flatten(),
+ this.options
+ );
+ }
+});
+
+Element.CSS_PROPERTIES = $w(
+ 'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' +
+ 'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +
+ 'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +
+ 'borderTopColor borderTopStyle borderTopWidth bottom clip color ' +
+ 'fontSize fontWeight height left letterSpacing lineHeight ' +
+ 'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+
+ 'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +
+ 'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +
+ 'right textIndent top width wordSpacing zIndex');
+
+Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
+
+String.__parseStyleElement = document.createElement('div');
+String.prototype.parseStyle = function(){
+ var style, styleRules = $H();
+ if (Prototype.Browser.WebKit)
+ style = new Element('div',{style:this}).style;
+ else {
+ String.__parseStyleElement.innerHTML = '<div style="' + this + '"></div>';
+ style = String.__parseStyleElement.childNodes[0].style;
+ }
+
+ Element.CSS_PROPERTIES.each(function(property){
+ if (style[property]) styleRules.set(property, style[property]);
+ });
+
+ if (Prototype.Browser.IE && this.include('opacity'))
+ styleRules.set('opacity', this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]);
+
+ return styleRules;
+};
+
+if (document.defaultView && document.defaultView.getComputedStyle) {
+ Element.getStyles = function(element) {
+ var css = document.defaultView.getComputedStyle($(element), null);
+ return Element.CSS_PROPERTIES.inject({ }, function(styles, property) {
+ styles[property] = css[property];
+ return styles;
+ });
+ };
+} else {
+ Element.getStyles = function(element) {
+ element = $(element);
+ var css = element.currentStyle, styles;
+ styles = Element.CSS_PROPERTIES.inject({ }, function(hash, property) {
+ hash.set(property, css[property]);
+ return hash;
+ });
+ if (!styles.opacity) styles.set('opacity', element.getOpacity());
+ return styles;
+ };
+};
+
+Effect.Methods = {
+ morph: function(element, style) {
+ element = $(element);
+ new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || { }));
+ return element;
+ },
+ visualEffect: function(element, effect, options) {
+ element = $(element)
+ var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1);
+ new Effect[klass](element, options);
+ return element;
+ },
+ highlight: function(element, options) {
+ element = $(element);
+ new Effect.Highlight(element, options);
+ return element;
+ }
+};
+
+$w('fade appear grow shrink fold blindUp blindDown slideUp slideDown '+
+ 'pulsate shake puff squish switchOff dropOut').each(
+ function(effect) {
+ Effect.Methods[effect] = function(element, options){
+ element = $(element);
+ Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options);
+ return element;
+ }
+ }
+);
+
+$w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each(
+ function(f) { Effect.Methods[f] = Element[f]; }
+);
+
+Element.addMethods(Effect.Methods);
diff --git a/vendor/rails-2.0.2/railties/html/javascripts/prototype.js b/vendor/rails-2.0.2/railties/html/javascripts/prototype.js
new file mode 100644
index 000000000..546f9fe44
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/html/javascripts/prototype.js
@@ -0,0 +1,4225 @@
+/* Prototype JavaScript framework, version 1.6.0.1
+ * (c) 2005-2007 Sam Stephenson
+ *
+ * Prototype is freely distributable under the terms of an MIT-style license.
+ * For details, see the Prototype web site: http://www.prototypejs.org/
+ *
+ *--------------------------------------------------------------------------*/
+
+var Prototype = {
+ Version: '1.6.0.1',
+
+ Browser: {
+ IE: !!(window.attachEvent && !window.opera),
+ Opera: !!window.opera,
+ WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
+ Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,
+ MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
+ },
+
+ BrowserFeatures: {
+ XPath: !!document.evaluate,
+ ElementExtensions: !!window.HTMLElement,
+ SpecificElementExtensions:
+ document.createElement('div').__proto__ &&
+ document.createElement('div').__proto__ !==
+ document.createElement('form').__proto__
+ },
+
+ ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
+ JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,
+
+ emptyFunction: function() { },
+ K: function(x) { return x }
+};
+
+if (Prototype.Browser.MobileSafari)
+ Prototype.BrowserFeatures.SpecificElementExtensions = false;
+
+
+/* Based on Alex Arnell's inheritance implementation. */
+var Class = {
+ create: function() {
+ var parent = null, properties = $A(arguments);
+ if (Object.isFunction(properties[0]))
+ parent = properties.shift();
+
+ function klass() {
+ this.initialize.apply(this, arguments);
+ }
+
+ Object.extend(klass, Class.Methods);
+ klass.superclass = parent;
+ klass.subclasses = [];
+
+ if (parent) {
+ var subclass = function() { };
+ subclass.prototype = parent.prototype;
+ klass.prototype = new subclass;
+ parent.subclasses.push(klass);
+ }
+
+ for (var i = 0; i < properties.length; i++)
+ klass.addMethods(properties[i]);
+
+ if (!klass.prototype.initialize)
+ klass.prototype.initialize = Prototype.emptyFunction;
+
+ klass.prototype.constructor = klass;
+
+ return klass;
+ }
+};
+
+Class.Methods = {
+ addMethods: function(source) {
+ var ancestor = this.superclass && this.superclass.prototype;
+ var properties = Object.keys(source);
+
+ if (!Object.keys({ toString: true }).length)
+ properties.push("toString", "valueOf");
+
+ for (var i = 0, length = properties.length; i < length; i++) {
+ var property = properties[i], value = source[property];
+ if (ancestor && Object.isFunction(value) &&
+ value.argumentNames().first() == "$super") {
+ var method = value, value = Object.extend((function(m) {
+ return function() { return ancestor[m].apply(this, arguments) };
+ })(property).wrap(method), {
+ valueOf: function() { return method },
+ toString: function() { return method.toString() }
+ });
+ }
+ this.prototype[property] = value;
+ }
+
+ return this;
+ }
+};
+
+var Abstract = { };
+
+Object.extend = function(destination, source) {
+ for (var property in source)
+ destination[property] = source[property];
+ return destination;
+};
+
+Object.extend(Object, {
+ inspect: function(object) {
+ try {
+ if (Object.isUndefined(object)) return 'undefined';
+ if (object === null) return 'null';
+ return object.inspect ? object.inspect() : object.toString();
+ } catch (e) {
+ if (e instanceof RangeError) return '...';
+ throw e;
+ }
+ },
+
+ toJSON: function(object) {
+ var type = typeof object;
+ switch (type) {
+ case 'undefined':
+ case 'function':
+ case 'unknown': return;
+ case 'boolean': return object.toString();
+ }
+
+ if (object === null) return 'null';
+ if (object.toJSON) return object.toJSON();
+ if (Object.isElement(object)) return;
+
+ var results = [];
+ for (var property in object) {
+ var value = Object.toJSON(object[property]);
+ if (!Object.isUndefined(value))
+ results.push(property.toJSON() + ': ' + value);
+ }
+
+ return '{' + results.join(', ') + '}';
+ },
+
+ toQueryString: function(object) {
+ return $H(object).toQueryString();
+ },
+
+ toHTML: function(object) {
+ return object && object.toHTML ? object.toHTML() : String.interpret(object);
+ },
+
+ keys: function(object) {
+ var keys = [];
+ for (var property in object)
+ keys.push(property);
+ return keys;
+ },
+
+ values: function(object) {
+ var values = [];
+ for (var property in object)
+ values.push(object[property]);
+ return values;
+ },
+
+ clone: function(object) {
+ return Object.extend({ }, object);
+ },
+
+ isElement: function(object) {
+ return object && object.nodeType == 1;
+ },
+
+ isArray: function(object) {
+ return object && object.constructor === Array;
+ },
+
+ isHash: function(object) {
+ return object instanceof Hash;
+ },
+
+ isFunction: function(object) {
+ return typeof object == "function";
+ },
+
+ isString: function(object) {
+ return typeof object == "string";
+ },
+
+ isNumber: function(object) {
+ return typeof object == "number";
+ },
+
+ isUndefined: function(object) {
+ return typeof object == "undefined";
+ }
+});
+
+Object.extend(Function.prototype, {
+ argumentNames: function() {
+ var names = this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip");
+ return names.length == 1 && !names[0] ? [] : names;
+ },
+
+ bind: function() {
+ if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
+ var __method = this, args = $A(arguments), object = args.shift();
+ return function() {
+ return __method.apply(object, args.concat($A(arguments)));
+ }
+ },
+
+ bindAsEventListener: function() {
+ var __method = this, args = $A(arguments), object = args.shift();
+ return function(event) {
+ return __method.apply(object, [event || window.event].concat(args));
+ }
+ },
+
+ curry: function() {
+ if (!arguments.length) return this;
+ var __method = this, args = $A(arguments);
+ return function() {
+ return __method.apply(this, args.concat($A(arguments)));
+ }
+ },
+
+ delay: function() {
+ var __method = this, args = $A(arguments), timeout = args.shift() * 1000;
+ return window.setTimeout(function() {
+ return __method.apply(__method, args);
+ }, timeout);
+ },
+
+ wrap: function(wrapper) {
+ var __method = this;
+ return function() {
+ return wrapper.apply(this, [__method.bind(this)].concat($A(arguments)));
+ }
+ },
+
+ methodize: function() {
+ if (this._methodized) return this._methodized;
+ var __method = this;
+ return this._methodized = function() {
+ return __method.apply(null, [this].concat($A(arguments)));
+ };
+ }
+});
+
+Function.prototype.defer = Function.prototype.delay.curry(0.01);
+
+Date.prototype.toJSON = function() {
+ return '"' + this.getUTCFullYear() + '-' +
+ (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
+ this.getUTCDate().toPaddedString(2) + 'T' +
+ this.getUTCHours().toPaddedString(2) + ':' +
+ this.getUTCMinutes().toPaddedString(2) + ':' +
+ this.getUTCSeconds().toPaddedString(2) + 'Z"';
+};
+
+var Try = {
+ these: function() {
+ var returnValue;
+
+ for (var i = 0, length = arguments.length; i < length; i++) {
+ var lambda = arguments[i];
+ try {
+ returnValue = lambda();
+ break;
+ } catch (e) { }
+ }
+
+ return returnValue;
+ }
+};
+
+RegExp.prototype.match = RegExp.prototype.test;
+
+RegExp.escape = function(str) {
+ return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
+};
+
+/*--------------------------------------------------------------------------*/
+
+var PeriodicalExecuter = Class.create({
+ initialize: function(callback, frequency) {
+ this.callback = callback;
+ this.frequency = frequency;
+ this.currentlyExecuting = false;
+
+ this.registerCallback();
+ },
+
+ registerCallback: function() {
+ this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
+ },
+
+ execute: function() {
+ this.callback(this);
+ },
+
+ stop: function() {
+ if (!this.timer) return;
+ clearInterval(this.timer);
+ this.timer = null;
+ },
+
+ onTimerEvent: function() {
+ if (!this.currentlyExecuting) {
+ try {
+ this.currentlyExecuting = true;
+ this.execute();
+ } finally {
+ this.currentlyExecuting = false;
+ }
+ }
+ }
+});
+Object.extend(String, {
+ interpret: function(value) {
+ return value == null ? '' : String(value);
+ },
+ specialChar: {
+ '\b': '\\b',
+ '\t': '\\t',
+ '\n': '\\n',
+ '\f': '\\f',
+ '\r': '\\r',
+ '\\': '\\\\'
+ }
+});
+
+Object.extend(String.prototype, {
+ gsub: function(pattern, replacement) {
+ var result = '', source = this, match;
+ replacement = arguments.callee.prepareReplacement(replacement);
+
+ while (source.length > 0) {
+ if (match = source.match(pattern)) {
+ result += source.slice(0, match.index);
+ result += String.interpret(replacement(match));
+ source = source.slice(match.index + match[0].length);
+ } else {
+ result += source, source = '';
+ }
+ }
+ return result;
+ },
+
+ sub: function(pattern, replacement, count) {
+ replacement = this.gsub.prepareReplacement(replacement);
+ count = Object.isUndefined(count) ? 1 : count;
+
+ return this.gsub(pattern, function(match) {
+ if (--count < 0) return match[0];
+ return replacement(match);
+ });
+ },
+
+ scan: function(pattern, iterator) {
+ this.gsub(pattern, iterator);
+ return String(this);
+ },
+
+ truncate: function(length, truncation) {
+ length = length || 30;
+ truncation = Object.isUndefined(truncation) ? '...' : truncation;
+ return this.length > length ?
+ this.slice(0, length - truncation.length) + truncation : String(this);
+ },
+
+ strip: function() {
+ return this.replace(/^\s+/, '').replace(/\s+$/, '');
+ },
+
+ stripTags: function() {
+ return this.replace(/<\/?[^>]+>/gi, '');
+ },
+
+ stripScripts: function() {
+ return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
+ },
+
+ extractScripts: function() {
+ var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
+ var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
+ return (this.match(matchAll) || []).map(function(scriptTag) {
+ return (scriptTag.match(matchOne) || ['', ''])[1];
+ });
+ },
+
+ evalScripts: function() {
+ return this.extractScripts().map(function(script) { return eval(script) });
+ },
+
+ escapeHTML: function() {
+ var self = arguments.callee;
+ self.text.data = this;
+ return self.div.innerHTML;
+ },
+
+ unescapeHTML: function() {
+ var div = new Element('div');
+ div.innerHTML = this.stripTags();
+ return div.childNodes[0] ? (div.childNodes.length > 1 ?
+ $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :
+ div.childNodes[0].nodeValue) : '';
+ },
+
+ toQueryParams: function(separator) {
+ var match = this.strip().match(/([^?#]*)(#.*)?$/);
+ if (!match) return { };
+
+ return match[1].split(separator || '&').inject({ }, function(hash, pair) {
+ if ((pair = pair.split('='))[0]) {
+ var key = decodeURIComponent(pair.shift());
+ var value = pair.length > 1 ? pair.join('=') : pair[0];
+ if (value != undefined) value = decodeURIComponent(value);
+
+ if (key in hash) {
+ if (!Object.isArray(hash[key])) hash[key] = [hash[key]];
+ hash[key].push(value);
+ }
+ else hash[key] = value;
+ }
+ return hash;
+ });
+ },
+
+ toArray: function() {
+ return this.split('');
+ },
+
+ succ: function() {
+ return this.slice(0, this.length - 1) +
+ String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
+ },
+
+ times: function(count) {
+ return count < 1 ? '' : new Array(count + 1).join(this);
+ },
+
+ camelize: function() {
+ var parts = this.split('-'), len = parts.length;
+ if (len == 1) return parts[0];
+
+ var camelized = this.charAt(0) == '-'
+ ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
+ : parts[0];
+
+ for (var i = 1; i < len; i++)
+ camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
+
+ return camelized;
+ },
+
+ capitalize: function() {
+ return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
+ },
+
+ underscore: function() {
+ return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
+ },
+
+ dasherize: function() {
+ return this.gsub(/_/,'-');
+ },
+
+ inspect: function(useDoubleQuotes) {
+ var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
+ var character = String.specialChar[match[0]];
+ return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
+ });
+ if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
+ return "'" + escapedString.replace(/'/g, '\\\'') + "'";
+ },
+
+ toJSON: function() {
+ return this.inspect(true);
+ },
+
+ unfilterJSON: function(filter) {
+ return this.sub(filter || Prototype.JSONFilter, '#{1}');
+ },
+
+ isJSON: function() {
+ var str = this;
+ if (str.blank()) return false;
+ str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
+ return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
+ },
+
+ evalJSON: function(sanitize) {
+ var json = this.unfilterJSON();
+ try {
+ if (!sanitize || json.isJSON()) return eval('(' + json + ')');
+ } catch (e) { }
+ throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
+ },
+
+ include: function(pattern) {
+ return this.indexOf(pattern) > -1;
+ },
+
+ startsWith: function(pattern) {
+ return this.indexOf(pattern) === 0;
+ },
+
+ endsWith: function(pattern) {
+ var d = this.length - pattern.length;
+ return d >= 0 && this.lastIndexOf(pattern) === d;
+ },
+
+ empty: function() {
+ return this == '';
+ },
+
+ blank: function() {
+ return /^\s*$/.test(this);
+ },
+
+ interpolate: function(object, pattern) {
+ return new Template(this, pattern).evaluate(object);
+ }
+});
+
+if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
+ escapeHTML: function() {
+ return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
+ },
+ unescapeHTML: function() {
+ return this.replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
+ }
+});
+
+String.prototype.gsub.prepareReplacement = function(replacement) {
+ if (Object.isFunction(replacement)) return replacement;
+ var template = new Template(replacement);
+ return function(match) { return template.evaluate(match) };
+};
+
+String.prototype.parseQuery = String.prototype.toQueryParams;
+
+Object.extend(String.prototype.escapeHTML, {
+ div: document.createElement('div'),
+ text: document.createTextNode('')
+});
+
+with (String.prototype.escapeHTML) div.appendChild(text);
+
+var Template = Class.create({
+ initialize: function(template, pattern) {
+ this.template = template.toString();
+ this.pattern = pattern || Template.Pattern;
+ },
+
+ evaluate: function(object) {
+ if (Object.isFunction(object.toTemplateReplacements))
+ object = object.toTemplateReplacements();
+
+ return this.template.gsub(this.pattern, function(match) {
+ if (object == null) return '';
+
+ var before = match[1] || '';
+ if (before == '\\') return match[2];
+
+ var ctx = object, expr = match[3];
+ var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
+ match = pattern.exec(expr);
+ if (match == null) return before;
+
+ while (match != null) {
+ var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1];
+ ctx = ctx[comp];
+ if (null == ctx || '' == match[3]) break;
+ expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
+ match = pattern.exec(expr);
+ }
+
+ return before + String.interpret(ctx);
+ }.bind(this));
+ }
+});
+Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
+
+var $break = { };
+
+var Enumerable = {
+ each: function(iterator, context) {
+ var index = 0;
+ iterator = iterator.bind(context);
+ try {
+ this._each(function(value) {
+ iterator(value, index++);
+ });
+ } catch (e) {
+ if (e != $break) throw e;
+ }
+ return this;
+ },
+
+ eachSlice: function(number, iterator, context) {
+ iterator = iterator ? iterator.bind(context) : Prototype.K;
+ var index = -number, slices = [], array = this.toArray();
+ while ((index += number) < array.length)
+ slices.push(array.slice(index, index+number));
+ return slices.collect(iterator, context);
+ },
+
+ all: function(iterator, context) {
+ iterator = iterator ? iterator.bind(context) : Prototype.K;
+ var result = true;
+ this.each(function(value, index) {
+ result = result && !!iterator(value, index);
+ if (!result) throw $break;
+ });
+ return result;
+ },
+
+ any: function(iterator, context) {
+ iterator = iterator ? iterator.bind(context) : Prototype.K;
+ var result = false;
+ this.each(function(value, index) {
+ if (result = !!iterator(value, index))
+ throw $break;
+ });
+ return result;
+ },
+
+ collect: function(iterator, context) {
+ iterator = iterator ? iterator.bind(context) : Prototype.K;
+ var results = [];
+ this.each(function(value, index) {
+ results.push(iterator(value, index));
+ });
+ return results;
+ },
+
+ detect: function(iterator, context) {
+ iterator = iterator.bind(context);
+ var result;
+ this.each(function(value, index) {
+ if (iterator(value, index)) {
+ result = value;
+ throw $break;
+ }
+ });
+ return result;
+ },
+
+ findAll: function(iterator, context) {
+ iterator = iterator.bind(context);
+ var results = [];
+ this.each(function(value, index) {
+ if (iterator(value, index))
+ results.push(value);
+ });
+ return results;
+ },
+
+ grep: function(filter, iterator, context) {
+ iterator = iterator ? iterator.bind(context) : Prototype.K;
+ var results = [];
+
+ if (Object.isString(filter))
+ filter = new RegExp(filter);
+
+ this.each(function(value, index) {
+ if (filter.match(value))
+ results.push(iterator(value, index));
+ });
+ return results;
+ },
+
+ include: function(object) {
+ if (Object.isFunction(this.indexOf))
+ if (this.indexOf(object) != -1) return true;
+
+ var found = false;
+ this.each(function(value) {
+ if (value == object) {
+ found = true;
+ throw $break;
+ }
+ });
+ return found;
+ },
+
+ inGroupsOf: function(number, fillWith) {
+ fillWith = Object.isUndefined(fillWith) ? null : fillWith;
+ return this.eachSlice(number, function(slice) {
+ while(slice.length < number) slice.push(fillWith);
+ return slice;
+ });
+ },
+
+ inject: function(memo, iterator, context) {
+ iterator = iterator.bind(context);
+ this.each(function(value, index) {
+ memo = iterator(memo, value, index);
+ });
+ return memo;
+ },
+
+ invoke: function(method) {
+ var args = $A(arguments).slice(1);
+ return this.map(function(value) {
+ return value[method].apply(value, args);
+ });
+ },
+
+ max: function(iterator, context) {
+ iterator = iterator ? iterator.bind(context) : Prototype.K;
+ var result;
+ this.each(function(value, index) {
+ value = iterator(value, index);
+ if (result == null || value >= result)
+ result = value;
+ });
+ return result;
+ },
+
+ min: function(iterator, context) {
+ iterator = iterator ? iterator.bind(context) : Prototype.K;
+ var result;
+ this.each(function(value, index) {
+ value = iterator(value, index);
+ if (result == null || value < result)
+ result = value;
+ });
+ return result;
+ },
+
+ partition: function(iterator, context) {
+ iterator = iterator ? iterator.bind(context) : Prototype.K;
+ var trues = [], falses = [];
+ this.each(function(value, index) {
+ (iterator(value, index) ?
+ trues : falses).push(value);
+ });
+ return [trues, falses];
+ },
+
+ pluck: function(property) {
+ var results = [];
+ this.each(function(value) {
+ results.push(value[property]);
+ });
+ return results;
+ },
+
+ reject: function(iterator, context) {
+ iterator = iterator.bind(context);
+ var results = [];
+ this.each(function(value, index) {
+ if (!iterator(value, index))
+ results.push(value);
+ });
+ return results;
+ },
+
+ sortBy: function(iterator, context) {
+ iterator = iterator.bind(context);
+ return this.map(function(value, index) {
+ return {value: value, criteria: iterator(value, index)};
+ }).sort(function(left, right) {
+ var a = left.criteria, b = right.criteria;
+ return a < b ? -1 : a > b ? 1 : 0;
+ }).pluck('value');
+ },
+
+ toArray: function() {
+ return this.map();
+ },
+
+ zip: function() {
+ var iterator = Prototype.K, args = $A(arguments);
+ if (Object.isFunction(args.last()))
+ iterator = args.pop();
+
+ var collections = [this].concat(args).map($A);
+ return this.map(function(value, index) {
+ return iterator(collections.pluck(index));
+ });
+ },
+
+ size: function() {
+ return this.toArray().length;
+ },
+
+ inspect: function() {
+ return '#<Enumerable:' + this.toArray().inspect() + '>';
+ }
+};
+
+Object.extend(Enumerable, {
+ map: Enumerable.collect,
+ find: Enumerable.detect,
+ select: Enumerable.findAll,
+ filter: Enumerable.findAll,
+ member: Enumerable.include,
+ entries: Enumerable.toArray,
+ every: Enumerable.all,
+ some: Enumerable.any
+});
+function $A(iterable) {
+ if (!iterable) return [];
+ if (iterable.toArray) return iterable.toArray();
+ var length = iterable.length, results = new Array(length);
+ while (length--) results[length] = iterable[length];
+ return results;
+}
+
+if (Prototype.Browser.WebKit) {
+ function $A(iterable) {
+ if (!iterable) return [];
+ if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') &&
+ iterable.toArray) return iterable.toArray();
+ var length = iterable.length, results = new Array(length);
+ while (length--) results[length] = iterable[length];
+ return results;
+ }
+}
+
+Array.from = $A;
+
+Object.extend(Array.prototype, Enumerable);
+
+if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse;
+
+Object.extend(Array.prototype, {
+ _each: function(iterator) {
+ for (var i = 0, length = this.length; i < length; i++)
+ iterator(this[i]);
+ },
+
+ clear: function() {
+ this.length = 0;
+ return this;
+ },
+
+ first: function() {
+ return this[0];
+ },
+
+ last: function() {
+ return this[this.length - 1];
+ },
+
+ compact: function() {
+ return this.select(function(value) {
+ return value != null;
+ });
+ },
+
+ flatten: function() {
+ return this.inject([], function(array, value) {
+ return array.concat(Object.isArray(value) ?
+ value.flatten() : [value]);
+ });
+ },
+
+ without: function() {
+ var values = $A(arguments);
+ return this.select(function(value) {
+ return !values.include(value);
+ });
+ },
+
+ reverse: function(inline) {
+ return (inline !== false ? this : this.toArray())._reverse();
+ },
+
+ reduce: function() {
+ return this.length > 1 ? this : this[0];
+ },
+
+ uniq: function(sorted) {
+ return this.inject([], function(array, value, index) {
+ if (0 == index || (sorted ? array.last() != value : !array.include(value)))
+ array.push(value);
+ return array;
+ });
+ },
+
+ intersect: function(array) {
+ return this.uniq().findAll(function(item) {
+ return array.detect(function(value) { return item === value });
+ });
+ },
+
+ clone: function() {
+ return [].concat(this);
+ },
+
+ size: function() {
+ return this.length;
+ },
+
+ inspect: function() {
+ return '[' + this.map(Object.inspect).join(', ') + ']';
+ },
+
+ toJSON: function() {
+ var results = [];
+ this.each(function(object) {
+ var value = Object.toJSON(object);
+ if (!Object.isUndefined(value)) results.push(value);
+ });
+ return '[' + results.join(', ') + ']';
+ }
+});
+
+// use native browser JS 1.6 implementation if available
+if (Object.isFunction(Array.prototype.forEach))
+ Array.prototype._each = Array.prototype.forEach;
+
+if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) {
+ i || (i = 0);
+ var length = this.length;
+ if (i < 0) i = length + i;
+ for (; i < length; i++)
+ if (this[i] === item) return i;
+ return -1;
+};
+
+if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) {
+ i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;
+ var n = this.slice(0, i).reverse().indexOf(item);
+ return (n < 0) ? n : i - n - 1;
+};
+
+Array.prototype.toArray = Array.prototype.clone;
+
+function $w(string) {
+ if (!Object.isString(string)) return [];
+ string = string.strip();
+ return string ? string.split(/\s+/) : [];
+}
+
+if (Prototype.Browser.Opera){
+ Array.prototype.concat = function() {
+ var array = [];
+ for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
+ for (var i = 0, length = arguments.length; i < length; i++) {
+ if (Object.isArray(arguments[i])) {
+ for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
+ array.push(arguments[i][j]);
+ } else {
+ array.push(arguments[i]);
+ }
+ }
+ return array;
+ };
+}
+Object.extend(Number.prototype, {
+ toColorPart: function() {
+ return this.toPaddedString(2, 16);
+ },
+
+ succ: function() {
+ return this + 1;
+ },
+
+ times: function(iterator) {
+ $R(0, this, true).each(iterator);
+ return this;
+ },
+
+ toPaddedString: function(length, radix) {
+ var string = this.toString(radix || 10);
+ return '0'.times(length - string.length) + string;
+ },
+
+ toJSON: function() {
+ return isFinite(this) ? this.toString() : 'null';
+ }
+});
+
+$w('abs round ceil floor').each(function(method){
+ Number.prototype[method] = Math[method].methodize();
+});
+function $H(object) {
+ return new Hash(object);
+};
+
+var Hash = Class.create(Enumerable, (function() {
+
+ function toQueryPair(key, value) {
+ if (Object.isUndefined(value)) return key;
+ return key + '=' + encodeURIComponent(String.interpret(value));
+ }
+
+ return {
+ initialize: function(object) {
+ this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
+ },
+
+ _each: function(iterator) {
+ for (var key in this._object) {
+ var value = this._object[key], pair = [key, value];
+ pair.key = key;
+ pair.value = value;
+ iterator(pair);
+ }
+ },
+
+ set: function(key, value) {
+ return this._object[key] = value;
+ },
+
+ get: function(key) {
+ return this._object[key];
+ },
+
+ unset: function(key) {
+ var value = this._object[key];
+ delete this._object[key];
+ return value;
+ },
+
+ toObject: function() {
+ return Object.clone(this._object);
+ },
+
+ keys: function() {
+ return this.pluck('key');
+ },
+
+ values: function() {
+ return this.pluck('value');
+ },
+
+ index: function(value) {
+ var match = this.detect(function(pair) {
+ return pair.value === value;
+ });
+ return match && match.key;
+ },
+
+ merge: function(object) {
+ return this.clone().update(object);
+ },
+
+ update: function(object) {
+ return new Hash(object).inject(this, function(result, pair) {
+ result.set(pair.key, pair.value);
+ return result;
+ });
+ },
+
+ toQueryString: function() {
+ return this.map(function(pair) {
+ var key = encodeURIComponent(pair.key), values = pair.value;
+
+ if (values && typeof values == 'object') {
+ if (Object.isArray(values))
+ return values.map(toQueryPair.curry(key)).join('&');
+ }
+ return toQueryPair(key, values);
+ }).join('&');
+ },
+
+ inspect: function() {
+ return '#<Hash:{' + this.map(function(pair) {
+ return pair.map(Object.inspect).join(': ');
+ }).join(', ') + '}>';
+ },
+
+ toJSON: function() {
+ return Object.toJSON(this.toObject());
+ },
+
+ clone: function() {
+ return new Hash(this);
+ }
+ }
+})());
+
+Hash.prototype.toTemplateReplacements = Hash.prototype.toObject;
+Hash.from = $H;
+var ObjectRange = Class.create(Enumerable, {
+ initialize: function(start, end, exclusive) {
+ this.start = start;
+ this.end = end;
+ this.exclusive = exclusive;
+ },
+
+ _each: function(iterator) {
+ var value = this.start;
+ while (this.include(value)) {
+ iterator(value);
+ value = value.succ();
+ }
+ },
+
+ include: function(value) {
+ if (value < this.start)
+ return false;
+ if (this.exclusive)
+ return value < this.end;
+ return value <= this.end;
+ }
+});
+
+var $R = function(start, end, exclusive) {
+ return new ObjectRange(start, end, exclusive);
+};
+
+var Ajax = {
+ getTransport: function() {
+ return Try.these(
+ function() {return new XMLHttpRequest()},
+ function() {return new ActiveXObject('Msxml2.XMLHTTP')},
+ function() {return new ActiveXObject('Microsoft.XMLHTTP')}
+ ) || false;
+ },
+
+ activeRequestCount: 0
+};
+
+Ajax.Responders = {
+ responders: [],
+
+ _each: function(iterator) {
+ this.responders._each(iterator);
+ },
+
+ register: function(responder) {
+ if (!this.include(responder))
+ this.responders.push(responder);
+ },
+
+ unregister: function(responder) {
+ this.responders = this.responders.without(responder);
+ },
+
+ dispatch: function(callback, request, transport, json) {
+ this.each(function(responder) {
+ if (Object.isFunction(responder[callback])) {
+ try {
+ responder[callback].apply(responder, [request, transport, json]);
+ } catch (e) { }
+ }
+ });
+ }
+};
+
+Object.extend(Ajax.Responders, Enumerable);
+
+Ajax.Responders.register({
+ onCreate: function() { Ajax.activeRequestCount++ },
+ onComplete: function() { Ajax.activeRequestCount-- }
+});
+
+Ajax.Base = Class.create({
+ initialize: function(options) {
+ this.options = {
+ method: 'post',
+ asynchronous: true,
+ contentType: 'application/x-www-form-urlencoded',
+ encoding: 'UTF-8',
+ parameters: '',
+ evalJSON: true,
+ evalJS: true
+ };
+ Object.extend(this.options, options || { });
+
+ this.options.method = this.options.method.toLowerCase();
+
+ if (Object.isString(this.options.parameters))
+ this.options.parameters = this.options.parameters.toQueryParams();
+ else if (Object.isHash(this.options.parameters))
+ this.options.parameters = this.options.parameters.toObject();
+ }
+});
+
+Ajax.Request = Class.create(Ajax.Base, {
+ _complete: false,
+
+ initialize: function($super, url, options) {
+ $super(options);
+ this.transport = Ajax.getTransport();
+ this.request(url);
+ },
+
+ request: function(url) {
+ this.url = url;
+ this.method = this.options.method;
+ var params = Object.clone(this.options.parameters);
+
+ if (!['get', 'post'].include(this.method)) {
+ // simulate other verbs over post
+ params['_method'] = this.method;
+ this.method = 'post';
+ }
+
+ this.parameters = params;
+
+ if (params = Object.toQueryString(params)) {
+ // when GET, append parameters to URL
+ if (this.method == 'get')
+ this.url += (this.url.include('?') ? '&' : '?') + params;
+ else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
+ params += '&_=';
+ }
+
+ try {
+ var response = new Ajax.Response(this);
+ if (this.options.onCreate) this.options.onCreate(response);
+ Ajax.Responders.dispatch('onCreate', this, response);
+
+ this.transport.open(this.method.toUpperCase(), this.url,
+ this.options.asynchronous);
+
+ if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);
+
+ this.transport.onreadystatechange = this.onStateChange.bind(this);
+ this.setRequestHeaders();
+
+ this.body = this.method == 'post' ? (this.options.postBody || params) : null;
+ this.transport.send(this.body);
+
+ /* Force Firefox to handle ready state 4 for synchronous requests */
+ if (!this.options.asynchronous && this.transport.overrideMimeType)
+ this.onStateChange();
+
+ }
+ catch (e) {
+ this.dispatchException(e);
+ }
+ },
+
+ onStateChange: function() {
+ var readyState = this.transport.readyState;
+ if (readyState > 1 && !((readyState == 4) && this._complete))
+ this.respondToReadyState(this.transport.readyState);
+ },
+
+ setRequestHeaders: function() {
+ var headers = {
+ 'X-Requested-With': 'XMLHttpRequest',
+ 'X-Prototype-Version': Prototype.Version,
+ 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
+ };
+
+ if (this.method == 'post') {
+ headers['Content-type'] = this.options.contentType +
+ (this.options.encoding ? '; charset=' + this.options.encoding : '');
+
+ /* Force "Connection: close" for older Mozilla browsers to work
+ * around a bug where XMLHttpRequest sends an incorrect
+ * Content-length header. See Mozilla Bugzilla #246651.
+ */
+ if (this.transport.overrideMimeType &&
+ (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
+ headers['Connection'] = 'close';
+ }
+
+ // user-defined headers
+ if (typeof this.options.requestHeaders == 'object') {
+ var extras = this.options.requestHeaders;
+
+ if (Object.isFunction(extras.push))
+ for (var i = 0, length = extras.length; i < length; i += 2)
+ headers[extras[i]] = extras[i+1];
+ else
+ $H(extras).each(function(pair) { headers[pair.key] = pair.value });
+ }
+
+ for (var name in headers)
+ this.transport.setRequestHeader(name, headers[name]);
+ },
+
+ success: function() {
+ var status = this.getStatus();
+ return !status || (status >= 200 && status < 300);
+ },
+
+ getStatus: function() {
+ try {
+ return this.transport.status || 0;
+ } catch (e) { return 0 }
+ },
+
+ respondToReadyState: function(readyState) {
+ var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);
+
+ if (state == 'Complete') {
+ try {
+ this._complete = true;
+ (this.options['on' + response.status]
+ || this.options['on' + (this.success() ? 'Success' : 'Failure')]
+ || Prototype.emptyFunction)(response, response.headerJSON);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+
+ var contentType = response.getHeader('Content-type');
+ if (this.options.evalJS == 'force'
+ || (this.options.evalJS && contentType
+ && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
+ this.evalResponse();
+ }
+
+ try {
+ (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);
+ Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+
+ if (state == 'Complete') {
+ // avoid memory leak in MSIE: clean up
+ this.transport.onreadystatechange = Prototype.emptyFunction;
+ }
+ },
+
+ getHeader: function(name) {
+ try {
+ return this.transport.getResponseHeader(name);
+ } catch (e) { return null }
+ },
+
+ evalResponse: function() {
+ try {
+ return eval((this.transport.responseText || '').unfilterJSON());
+ } catch (e) {
+ this.dispatchException(e);
+ }
+ },
+
+ dispatchException: function(exception) {
+ (this.options.onException || Prototype.emptyFunction)(this, exception);
+ Ajax.Responders.dispatch('onException', this, exception);
+ }
+});
+
+Ajax.Request.Events =
+ ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
+
+Ajax.Response = Class.create({
+ initialize: function(request){
+ this.request = request;
+ var transport = this.transport = request.transport,
+ readyState = this.readyState = transport.readyState;
+
+ if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
+ this.status = this.getStatus();
+ this.statusText = this.getStatusText();
+ this.responseText = String.interpret(transport.responseText);
+ this.headerJSON = this._getHeaderJSON();
+ }
+
+ if(readyState == 4) {
+ var xml = transport.responseXML;
+ this.responseXML = Object.isUndefined(xml) ? null : xml;
+ this.responseJSON = this._getResponseJSON();
+ }
+ },
+
+ status: 0,
+ statusText: '',
+
+ getStatus: Ajax.Request.prototype.getStatus,
+
+ getStatusText: function() {
+ try {
+ return this.transport.statusText || '';
+ } catch (e) { return '' }
+ },
+
+ getHeader: Ajax.Request.prototype.getHeader,
+
+ getAllHeaders: function() {
+ try {
+ return this.getAllResponseHeaders();
+ } catch (e) { return null }
+ },
+
+ getResponseHeader: function(name) {
+ return this.transport.getResponseHeader(name);
+ },
+
+ getAllResponseHeaders: function() {
+ return this.transport.getAllResponseHeaders();
+ },
+
+ _getHeaderJSON: function() {
+ var json = this.getHeader('X-JSON');
+ if (!json) return null;
+ json = decodeURIComponent(escape(json));
+ try {
+ return json.evalJSON(this.request.options.sanitizeJSON);
+ } catch (e) {
+ this.request.dispatchException(e);
+ }
+ },
+
+ _getResponseJSON: function() {
+ var options = this.request.options;
+ if (!options.evalJSON || (options.evalJSON != 'force' &&
+ !(this.getHeader('Content-type') || '').include('application/json')) ||
+ this.responseText.blank())
+ return null;
+ try {
+ return this.responseText.evalJSON(options.sanitizeJSON);
+ } catch (e) {
+ this.request.dispatchException(e);
+ }
+ }
+});
+
+Ajax.Updater = Class.create(Ajax.Request, {
+ initialize: function($super, container, url, options) {
+ this.container = {
+ success: (container.success || container),
+ failure: (container.failure || (container.success ? null : container))
+ };
+
+ options = Object.clone(options);
+ var onComplete = options.onComplete;
+ options.onComplete = (function(response, json) {
+ this.updateContent(response.responseText);
+ if (Object.isFunction(onComplete)) onComplete(response, json);
+ }).bind(this);
+
+ $super(url, options);
+ },
+
+ updateContent: function(responseText) {
+ var receiver = this.container[this.success() ? 'success' : 'failure'],
+ options = this.options;
+
+ if (!options.evalScripts) responseText = responseText.stripScripts();
+
+ if (receiver = $(receiver)) {
+ if (options.insertion) {
+ if (Object.isString(options.insertion)) {
+ var insertion = { }; insertion[options.insertion] = responseText;
+ receiver.insert(insertion);
+ }
+ else options.insertion(receiver, responseText);
+ }
+ else receiver.update(responseText);
+ }
+ }
+});
+
+Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
+ initialize: function($super, container, url, options) {
+ $super(options);
+ this.onComplete = this.options.onComplete;
+
+ this.frequency = (this.options.frequency || 2);
+ this.decay = (this.options.decay || 1);
+
+ this.updater = { };
+ this.container = container;
+ this.url = url;
+
+ this.start();
+ },
+
+ start: function() {
+ this.options.onComplete = this.updateComplete.bind(this);
+ this.onTimerEvent();
+ },
+
+ stop: function() {
+ this.updater.options.onComplete = undefined;
+ clearTimeout(this.timer);
+ (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
+ },
+
+ updateComplete: function(response) {
+ if (this.options.decay) {
+ this.decay = (response.responseText == this.lastText ?
+ this.decay * this.options.decay : 1);
+
+ this.lastText = response.responseText;
+ }
+ this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);
+ },
+
+ onTimerEvent: function() {
+ this.updater = new Ajax.Updater(this.container, this.url, this.options);
+ }
+});
+function $(element) {
+ if (arguments.length > 1) {
+ for (var i = 0, elements = [], length = arguments.length; i < length; i++)
+ elements.push($(arguments[i]));
+ return elements;
+ }
+ if (Object.isString(element))
+ element = document.getElementById(element);
+ return Element.extend(element);
+}
+
+if (Prototype.BrowserFeatures.XPath) {
+ document._getElementsByXPath = function(expression, parentElement) {
+ var results = [];
+ var query = document.evaluate(expression, $(parentElement) || document,
+ null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
+ for (var i = 0, length = query.snapshotLength; i < length; i++)
+ results.push(Element.extend(query.snapshotItem(i)));
+ return results;
+ };
+}
+
+/*--------------------------------------------------------------------------*/
+
+if (!window.Node) var Node = { };
+
+if (!Node.ELEMENT_NODE) {
+ // DOM level 2 ECMAScript Language Binding
+ Object.extend(Node, {
+ ELEMENT_NODE: 1,
+ ATTRIBUTE_NODE: 2,
+ TEXT_NODE: 3,
+ CDATA_SECTION_NODE: 4,
+ ENTITY_REFERENCE_NODE: 5,
+ ENTITY_NODE: 6,
+ PROCESSING_INSTRUCTION_NODE: 7,
+ COMMENT_NODE: 8,
+ DOCUMENT_NODE: 9,
+ DOCUMENT_TYPE_NODE: 10,
+ DOCUMENT_FRAGMENT_NODE: 11,
+ NOTATION_NODE: 12
+ });
+}
+
+(function() {
+ var element = this.Element;
+ this.Element = function(tagName, attributes) {
+ attributes = attributes || { };
+ tagName = tagName.toLowerCase();
+ var cache = Element.cache;
+ if (Prototype.Browser.IE && attributes.name) {
+ tagName = '<' + tagName + ' name="' + attributes.name + '">';
+ delete attributes.name;
+ return Element.writeAttribute(document.createElement(tagName), attributes);
+ }
+ if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));
+ return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);
+ };
+ Object.extend(this.Element, element || { });
+}).call(window);
+
+Element.cache = { };
+
+Element.Methods = {
+ visible: function(element) {
+ return $(element).style.display != 'none';
+ },
+
+ toggle: function(element) {
+ element = $(element);
+ Element[Element.visible(element) ? 'hide' : 'show'](element);
+ return element;
+ },
+
+ hide: function(element) {
+ $(element).style.display = 'none';
+ return element;
+ },
+
+ show: function(element) {
+ $(element).style.display = '';
+ return element;
+ },
+
+ remove: function(element) {
+ element = $(element);
+ element.parentNode.removeChild(element);
+ return element;
+ },
+
+ update: function(element, content) {
+ element = $(element);
+ if (content && content.toElement) content = content.toElement();
+ if (Object.isElement(content)) return element.update().insert(content);
+ content = Object.toHTML(content);
+ element.innerHTML = content.stripScripts();
+ content.evalScripts.bind(content).defer();
+ return element;
+ },
+
+ replace: function(element, content) {
+ element = $(element);
+ if (content && content.toElement) content = content.toElement();
+ else if (!Object.isElement(content)) {
+ content = Object.toHTML(content);
+ var range = element.ownerDocument.createRange();
+ range.selectNode(element);
+ content.evalScripts.bind(content).defer();
+ content = range.createContextualFragment(content.stripScripts());
+ }
+ element.parentNode.replaceChild(content, element);
+ return element;
+ },
+
+ insert: function(element, insertions) {
+ element = $(element);
+
+ if (Object.isString(insertions) || Object.isNumber(insertions) ||
+ Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
+ insertions = {bottom:insertions};
+
+ var content, t, range;
+
+ for (position in insertions) {
+ content = insertions[position];
+ position = position.toLowerCase();
+ t = Element._insertionTranslations[position];
+
+ if (content && content.toElement) content = content.toElement();
+ if (Object.isElement(content)) {
+ t.insert(element, content);
+ continue;
+ }
+
+ content = Object.toHTML(content);
+
+ range = element.ownerDocument.createRange();
+ t.initializeRange(element, range);
+ t.insert(element, range.createContextualFragment(content.stripScripts()));
+
+ content.evalScripts.bind(content).defer();
+ }
+
+ return element;
+ },
+
+ wrap: function(element, wrapper, attributes) {
+ element = $(element);
+ if (Object.isElement(wrapper))
+ $(wrapper).writeAttribute(attributes || { });
+ else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes);
+ else wrapper = new Element('div', wrapper);
+ if (element.parentNode)
+ element.parentNode.replaceChild(wrapper, element);
+ wrapper.appendChild(element);
+ return wrapper;
+ },
+
+ inspect: function(element) {
+ element = $(element);
+ var result = '<' + element.tagName.toLowerCase();
+ $H({'id': 'id', 'className': 'class'}).each(function(pair) {
+ var property = pair.first(), attribute = pair.last();
+ var value = (element[property] || '').toString();
+ if (value) result += ' ' + attribute + '=' + value.inspect(true);
+ });
+ return result + '>';
+ },
+
+ recursivelyCollect: function(element, property) {
+ element = $(element);
+ var elements = [];
+ while (element = element[property])
+ if (element.nodeType == 1)
+ elements.push(Element.extend(element));
+ return elements;
+ },
+
+ ancestors: function(element) {
+ return $(element).recursivelyCollect('parentNode');
+ },
+
+ descendants: function(element) {
+ return $(element).getElementsBySelector("*");
+ },
+
+ firstDescendant: function(element) {
+ element = $(element).firstChild;
+ while (element && element.nodeType != 1) element = element.nextSibling;
+ return $(element);
+ },
+
+ immediateDescendants: function(element) {
+ if (!(element = $(element).firstChild)) return [];
+ while (element && element.nodeType != 1) element = element.nextSibling;
+ if (element) return [element].concat($(element).nextSiblings());
+ return [];
+ },
+
+ previousSiblings: function(element) {
+ return $(element).recursivelyCollect('previousSibling');
+ },
+
+ nextSiblings: function(element) {
+ return $(element).recursivelyCollect('nextSibling');
+ },
+
+ siblings: function(element) {
+ element = $(element);
+ return element.previousSiblings().reverse().concat(element.nextSiblings());
+ },
+
+ match: function(element, selector) {
+ if (Object.isString(selector))
+ selector = new Selector(selector);
+ return selector.match($(element));
+ },
+
+ up: function(element, expression, index) {
+ element = $(element);
+ if (arguments.length == 1) return $(element.parentNode);
+ var ancestors = element.ancestors();
+ return expression ? Selector.findElement(ancestors, expression, index) :
+ ancestors[index || 0];
+ },
+
+ down: function(element, expression, index) {
+ element = $(element);
+ if (arguments.length == 1) return element.firstDescendant();
+ var descendants = element.descendants();
+ return expression ? Selector.findElement(descendants, expression, index) :
+ descendants[index || 0];
+ },
+
+ previous: function(element, expression, index) {
+ element = $(element);
+ if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
+ var previousSiblings = element.previousSiblings();
+ return expression ? Selector.findElement(previousSiblings, expression, index) :
+ previousSiblings[index || 0];
+ },
+
+ next: function(element, expression, index) {
+ element = $(element);
+ if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
+ var nextSiblings = element.nextSiblings();
+ return expression ? Selector.findElement(nextSiblings, expression, index) :
+ nextSiblings[index || 0];
+ },
+
+ select: function() {
+ var args = $A(arguments), element = $(args.shift());
+ return Selector.findChildElements(element, args);
+ },
+
+ adjacent: function() {
+ var args = $A(arguments), element = $(args.shift());
+ return Selector.findChildElements(element.parentNode, args).without(element);
+ },
+
+ identify: function(element) {
+ element = $(element);
+ var id = element.readAttribute('id'), self = arguments.callee;
+ if (id) return id;
+ do { id = 'anonymous_element_' + self.counter++ } while ($(id));
+ element.writeAttribute('id', id);
+ return id;
+ },
+
+ readAttribute: function(element, name) {
+ element = $(element);
+ if (Prototype.Browser.IE) {
+ var t = Element._attributeTranslations.read;
+ if (t.values[name]) return t.values[name](element, name);
+ if (t.names[name]) name = t.names[name];
+ if (name.include(':')) {
+ return (!element.attributes || !element.attributes[name]) ? null :
+ element.attributes[name].value;
+ }
+ }
+ return element.getAttribute(name);
+ },
+
+ writeAttribute: function(element, name, value) {
+ element = $(element);
+ var attributes = { }, t = Element._attributeTranslations.write;
+
+ if (typeof name == 'object') attributes = name;
+ else attributes[name] = Object.isUndefined(value) ? true : value;
+
+ for (var attr in attributes) {
+ name = t.names[attr] || attr;
+ value = attributes[attr];
+ if (t.values[attr]) name = t.values[attr](element, value);
+ if (value === false || value === null)
+ element.removeAttribute(name);
+ else if (value === true)
+ element.setAttribute(name, name);
+ else element.setAttribute(name, value);
+ }
+ return element;
+ },
+
+ getHeight: function(element) {
+ return $(element).getDimensions().height;
+ },
+
+ getWidth: function(element) {
+ return $(element).getDimensions().width;
+ },
+
+ classNames: function(element) {
+ return new Element.ClassNames(element);
+ },
+
+ hasClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ var elementClassName = element.className;
+ return (elementClassName.length > 0 && (elementClassName == className ||
+ new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName)));
+ },
+
+ addClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ if (!element.hasClassName(className))
+ element.className += (element.className ? ' ' : '') + className;
+ return element;
+ },
+
+ removeClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ element.className = element.className.replace(
+ new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip();
+ return element;
+ },
+
+ toggleClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ return element[element.hasClassName(className) ?
+ 'removeClassName' : 'addClassName'](className);
+ },
+
+ // removes whitespace-only text node children
+ cleanWhitespace: function(element) {
+ element = $(element);
+ var node = element.firstChild;
+ while (node) {
+ var nextNode = node.nextSibling;
+ if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
+ element.removeChild(node);
+ node = nextNode;
+ }
+ return element;
+ },
+
+ empty: function(element) {
+ return $(element).innerHTML.blank();
+ },
+
+ descendantOf: function(element, ancestor) {
+ element = $(element), ancestor = $(ancestor);
+ var originalAncestor = ancestor;
+
+ if (element.compareDocumentPosition)
+ return (element.compareDocumentPosition(ancestor) & 8) === 8;
+
+ if (element.sourceIndex && !Prototype.Browser.Opera) {
+ var e = element.sourceIndex, a = ancestor.sourceIndex,
+ nextAncestor = ancestor.nextSibling;
+ if (!nextAncestor) {
+ do { ancestor = ancestor.parentNode; }
+ while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode);
+ }
+ if (nextAncestor) return (e > a && e < nextAncestor.sourceIndex);
+ }
+
+ while (element = element.parentNode)
+ if (element == originalAncestor) return true;
+ return false;
+ },
+
+ scrollTo: function(element) {
+ element = $(element);
+ var pos = element.cumulativeOffset();
+ window.scrollTo(pos[0], pos[1]);
+ return element;
+ },
+
+ getStyle: function(element, style) {
+ element = $(element);
+ style = style == 'float' ? 'cssFloat' : style.camelize();
+ var value = element.style[style];
+ if (!value) {
+ var css = document.defaultView.getComputedStyle(element, null);
+ value = css ? css[style] : null;
+ }
+ if (style == 'opacity') return value ? parseFloat(value) : 1.0;
+ return value == 'auto' ? null : value;
+ },
+
+ getOpacity: function(element) {
+ return $(element).getStyle('opacity');
+ },
+
+ setStyle: function(element, styles) {
+ element = $(element);
+ var elementStyle = element.style, match;
+ if (Object.isString(styles)) {
+ element.style.cssText += ';' + styles;
+ return styles.include('opacity') ?
+ element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element;
+ }
+ for (var property in styles)
+ if (property == 'opacity') element.setOpacity(styles[property]);
+ else
+ elementStyle[(property == 'float' || property == 'cssFloat') ?
+ (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') :
+ property] = styles[property];
+
+ return element;
+ },
+
+ setOpacity: function(element, value) {
+ element = $(element);
+ element.style.opacity = (value == 1 || value === '') ? '' :
+ (value < 0.00001) ? 0 : value;
+ return element;
+ },
+
+ getDimensions: function(element) {
+ element = $(element);
+ var display = $(element).getStyle('display');
+ if (display != 'none' && display != null) // Safari bug
+ return {width: element.offsetWidth, height: element.offsetHeight};
+
+ // All *Width and *Height properties give 0 on elements with display none,
+ // so enable the element temporarily
+ var els = element.style;
+ var originalVisibility = els.visibility;
+ var originalPosition = els.position;
+ var originalDisplay = els.display;
+ els.visibility = 'hidden';
+ els.position = 'absolute';
+ els.display = 'block';
+ var originalWidth = element.clientWidth;
+ var originalHeight = element.clientHeight;
+ els.display = originalDisplay;
+ els.position = originalPosition;
+ els.visibility = originalVisibility;
+ return {width: originalWidth, height: originalHeight};
+ },
+
+ makePositioned: function(element) {
+ element = $(element);
+ var pos = Element.getStyle(element, 'position');
+ if (pos == 'static' || !pos) {
+ element._madePositioned = true;
+ element.style.position = 'relative';
+ // Opera returns the offset relative to the positioning context, when an
+ // element is position relative but top and left have not been defined
+ if (window.opera) {
+ element.style.top = 0;
+ element.style.left = 0;
+ }
+ }
+ return element;
+ },
+
+ undoPositioned: function(element) {
+ element = $(element);
+ if (element._madePositioned) {
+ element._madePositioned = undefined;
+ element.style.position =
+ element.style.top =
+ element.style.left =
+ element.style.bottom =
+ element.style.right = '';
+ }
+ return element;
+ },
+
+ makeClipping: function(element) {
+ element = $(element);
+ if (element._overflow) return element;
+ element._overflow = Element.getStyle(element, 'overflow') || 'auto';
+ if (element._overflow !== 'hidden')
+ element.style.overflow = 'hidden';
+ return element;
+ },
+
+ undoClipping: function(element) {
+ element = $(element);
+ if (!element._overflow) return element;
+ element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
+ element._overflow = null;
+ return element;
+ },
+
+ cumulativeOffset: function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ element = element.offsetParent;
+ } while (element);
+ return Element._returnOffset(valueL, valueT);
+ },
+
+ positionedOffset: function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ element = element.offsetParent;
+ if (element) {
+ if (element.tagName == 'BODY') break;
+ var p = Element.getStyle(element, 'position');
+ if (p == 'relative' || p == 'absolute') break;
+ }
+ } while (element);
+ return Element._returnOffset(valueL, valueT);
+ },
+
+ absolutize: function(element) {
+ element = $(element);
+ if (element.getStyle('position') == 'absolute') return;
+ // Position.prepare(); // To be done manually by Scripty when it needs it.
+
+ var offsets = element.positionedOffset();
+ var top = offsets[1];
+ var left = offsets[0];
+ var width = element.clientWidth;
+ var height = element.clientHeight;
+
+ element._originalLeft = left - parseFloat(element.style.left || 0);
+ element._originalTop = top - parseFloat(element.style.top || 0);
+ element._originalWidth = element.style.width;
+ element._originalHeight = element.style.height;
+
+ element.style.position = 'absolute';
+ element.style.top = top + 'px';
+ element.style.left = left + 'px';
+ element.style.width = width + 'px';
+ element.style.height = height + 'px';
+ return element;
+ },
+
+ relativize: function(element) {
+ element = $(element);
+ if (element.getStyle('position') == 'relative') return;
+ // Position.prepare(); // To be done manually by Scripty when it needs it.
+
+ element.style.position = 'relative';
+ var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
+ var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
+
+ element.style.top = top + 'px';
+ element.style.left = left + 'px';
+ element.style.height = element._originalHeight;
+ element.style.width = element._originalWidth;
+ return element;
+ },
+
+ cumulativeScrollOffset: function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.scrollTop || 0;
+ valueL += element.scrollLeft || 0;
+ element = element.parentNode;
+ } while (element);
+ return Element._returnOffset(valueL, valueT);
+ },
+
+ getOffsetParent: function(element) {
+ if (element.offsetParent) return $(element.offsetParent);
+ if (element == document.body) return $(element);
+
+ while ((element = element.parentNode) && element != document.body)
+ if (Element.getStyle(element, 'position') != 'static')
+ return $(element);
+
+ return $(document.body);
+ },
+
+ viewportOffset: function(forElement) {
+ var valueT = 0, valueL = 0;
+
+ var element = forElement;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+
+ // Safari fix
+ if (element.offsetParent == document.body &&
+ Element.getStyle(element, 'position') == 'absolute') break;
+
+ } while (element = element.offsetParent);
+
+ element = forElement;
+ do {
+ if (!Prototype.Browser.Opera || element.tagName == 'BODY') {
+ valueT -= element.scrollTop || 0;
+ valueL -= element.scrollLeft || 0;
+ }
+ } while (element = element.parentNode);
+
+ return Element._returnOffset(valueL, valueT);
+ },
+
+ clonePosition: function(element, source) {
+ var options = Object.extend({
+ setLeft: true,
+ setTop: true,
+ setWidth: true,
+ setHeight: true,
+ offsetTop: 0,
+ offsetLeft: 0
+ }, arguments[2] || { });
+
+ // find page position of source
+ source = $(source);
+ var p = source.viewportOffset();
+
+ // find coordinate system to use
+ element = $(element);
+ var delta = [0, 0];
+ var parent = null;
+ // delta [0,0] will do fine with position: fixed elements,
+ // position:absolute needs offsetParent deltas
+ if (Element.getStyle(element, 'position') == 'absolute') {
+ parent = element.getOffsetParent();
+ delta = parent.viewportOffset();
+ }
+
+ // correct by body offsets (fixes Safari)
+ if (parent == document.body) {
+ delta[0] -= document.body.offsetLeft;
+ delta[1] -= document.body.offsetTop;
+ }
+
+ // set position
+ if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
+ if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
+ if (options.setWidth) element.style.width = source.offsetWidth + 'px';
+ if (options.setHeight) element.style.height = source.offsetHeight + 'px';
+ return element;
+ }
+};
+
+Element.Methods.identify.counter = 1;
+
+Object.extend(Element.Methods, {
+ getElementsBySelector: Element.Methods.select,
+ childElements: Element.Methods.immediateDescendants
+});
+
+Element._attributeTranslations = {
+ write: {
+ names: {
+ className: 'class',
+ htmlFor: 'for'
+ },
+ values: { }
+ }
+};
+
+
+if (!document.createRange || Prototype.Browser.Opera) {
+ Element.Methods.insert = function(element, insertions) {
+ element = $(element);
+
+ if (Object.isString(insertions) || Object.isNumber(insertions) ||
+ Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
+ insertions = { bottom: insertions };
+
+ var t = Element._insertionTranslations, content, position, pos, tagName;
+
+ for (position in insertions) {
+ content = insertions[position];
+ position = position.toLowerCase();
+ pos = t[position];
+
+ if (content && content.toElement) content = content.toElement();
+ if (Object.isElement(content)) {
+ pos.insert(element, content);
+ continue;
+ }
+
+ content = Object.toHTML(content);
+ tagName = ((position == 'before' || position == 'after')
+ ? element.parentNode : element).tagName.toUpperCase();
+
+ if (t.tags[tagName]) {
+ var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
+ if (position == 'top' || position == 'after') fragments.reverse();
+ fragments.each(pos.insert.curry(element));
+ }
+ else element.insertAdjacentHTML(pos.adjacency, content.stripScripts());
+
+ content.evalScripts.bind(content).defer();
+ }
+
+ return element;
+ };
+}
+
+if (Prototype.Browser.Opera) {
+ Element.Methods.getStyle = Element.Methods.getStyle.wrap(
+ function(proceed, element, style) {
+ switch (style) {
+ case 'left': case 'top': case 'right': case 'bottom':
+ if (proceed(element, 'position') === 'static') return null;
+ case 'height': case 'width':
+ // returns '0px' for hidden elements; we want it to return null
+ if (!Element.visible(element)) return null;
+
+ // returns the border-box dimensions rather than the content-box
+ // dimensions, so we subtract padding and borders from the value
+ var dim = parseInt(proceed(element, style), 10);
+
+ if (dim !== element['offset' + style.capitalize()])
+ return dim + 'px';
+
+ var properties;
+ if (style === 'height') {
+ properties = ['border-top-width', 'padding-top',
+ 'padding-bottom', 'border-bottom-width'];
+ }
+ else {
+ properties = ['border-left-width', 'padding-left',
+ 'padding-right', 'border-right-width'];
+ }
+ return properties.inject(dim, function(memo, property) {
+ var val = proceed(element, property);
+ return val === null ? memo : memo - parseInt(val, 10);
+ }) + 'px';
+ default: return proceed(element, style);
+ }
+ }
+ );
+
+ Element.Methods.readAttribute = Element.Methods.readAttribute.wrap(
+ function(proceed, element, attribute) {
+ if (attribute === 'title') return element.title;
+ return proceed(element, attribute);
+ }
+ );
+}
+
+else if (Prototype.Browser.IE) {
+ $w('positionedOffset getOffsetParent viewportOffset').each(function(method) {
+ Element.Methods[method] = Element.Methods[method].wrap(
+ function(proceed, element) {
+ element = $(element);
+ var position = element.getStyle('position');
+ if (position != 'static') return proceed(element);
+ element.setStyle({ position: 'relative' });
+ var value = proceed(element);
+ element.setStyle({ position: position });
+ return value;
+ }
+ );
+ });
+
+ Element.Methods.getStyle = function(element, style) {
+ element = $(element);
+ style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
+ var value = element.style[style];
+ if (!value && element.currentStyle) value = element.currentStyle[style];
+
+ if (style == 'opacity') {
+ if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
+ if (value[1]) return parseFloat(value[1]) / 100;
+ return 1.0;
+ }
+
+ if (value == 'auto') {
+ if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
+ return element['offset' + style.capitalize()] + 'px';
+ return null;
+ }
+ return value;
+ };
+
+ Element.Methods.setOpacity = function(element, value) {
+ function stripAlpha(filter){
+ return filter.replace(/alpha\([^\)]*\)/gi,'');
+ }
+ element = $(element);
+ var currentStyle = element.currentStyle;
+ if ((currentStyle && !currentStyle.hasLayout) ||
+ (!currentStyle && element.style.zoom == 'normal'))
+ element.style.zoom = 1;
+
+ var filter = element.getStyle('filter'), style = element.style;
+ if (value == 1 || value === '') {
+ (filter = stripAlpha(filter)) ?
+ style.filter = filter : style.removeAttribute('filter');
+ return element;
+ } else if (value < 0.00001) value = 0;
+ style.filter = stripAlpha(filter) +
+ 'alpha(opacity=' + (value * 100) + ')';
+ return element;
+ };
+
+ Element._attributeTranslations = {
+ read: {
+ names: {
+ 'class': 'className',
+ 'for': 'htmlFor'
+ },
+ values: {
+ _getAttr: function(element, attribute) {
+ return element.getAttribute(attribute, 2);
+ },
+ _getAttrNode: function(element, attribute) {
+ var node = element.getAttributeNode(attribute);
+ return node ? node.value : "";
+ },
+ _getEv: function(element, attribute) {
+ attribute = element.getAttribute(attribute);
+ return attribute ? attribute.toString().slice(23, -2) : null;
+ },
+ _flag: function(element, attribute) {
+ return $(element).hasAttribute(attribute) ? attribute : null;
+ },
+ style: function(element) {
+ return element.style.cssText.toLowerCase();
+ },
+ title: function(element) {
+ return element.title;
+ }
+ }
+ }
+ };
+
+ Element._attributeTranslations.write = {
+ names: Object.clone(Element._attributeTranslations.read.names),
+ values: {
+ checked: function(element, value) {
+ element.checked = !!value;
+ },
+
+ style: function(element, value) {
+ element.style.cssText = value ? value : '';
+ }
+ }
+ };
+
+ Element._attributeTranslations.has = {};
+
+ $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
+ 'encType maxLength readOnly longDesc').each(function(attr) {
+ Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
+ Element._attributeTranslations.has[attr.toLowerCase()] = attr;
+ });
+
+ (function(v) {
+ Object.extend(v, {
+ href: v._getAttr,
+ src: v._getAttr,
+ type: v._getAttr,
+ action: v._getAttrNode,
+ disabled: v._flag,
+ checked: v._flag,
+ readonly: v._flag,
+ multiple: v._flag,
+ onload: v._getEv,
+ onunload: v._getEv,
+ onclick: v._getEv,
+ ondblclick: v._getEv,
+ onmousedown: v._getEv,
+ onmouseup: v._getEv,
+ onmouseover: v._getEv,
+ onmousemove: v._getEv,
+ onmouseout: v._getEv,
+ onfocus: v._getEv,
+ onblur: v._getEv,
+ onkeypress: v._getEv,
+ onkeydown: v._getEv,
+ onkeyup: v._getEv,
+ onsubmit: v._getEv,
+ onreset: v._getEv,
+ onselect: v._getEv,
+ onchange: v._getEv
+ });
+ })(Element._attributeTranslations.read.values);
+}
+
+else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) {
+ Element.Methods.setOpacity = function(element, value) {
+ element = $(element);
+ element.style.opacity = (value == 1) ? 0.999999 :
+ (value === '') ? '' : (value < 0.00001) ? 0 : value;
+ return element;
+ };
+}
+
+else if (Prototype.Browser.WebKit) {
+ Element.Methods.setOpacity = function(element, value) {
+ element = $(element);
+ element.style.opacity = (value == 1 || value === '') ? '' :
+ (value < 0.00001) ? 0 : value;
+
+ if (value == 1)
+ if(element.tagName == 'IMG' && element.width) {
+ element.width++; element.width--;
+ } else try {
+ var n = document.createTextNode(' ');
+ element.appendChild(n);
+ element.removeChild(n);
+ } catch (e) { }
+
+ return element;
+ };
+
+ // Safari returns margins on body which is incorrect if the child is absolutely
+ // positioned. For performance reasons, redefine Element#cumulativeOffset for
+ // KHTML/WebKit only.
+ Element.Methods.cumulativeOffset = function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ if (element.offsetParent == document.body)
+ if (Element.getStyle(element, 'position') == 'absolute') break;
+
+ element = element.offsetParent;
+ } while (element);
+
+ return Element._returnOffset(valueL, valueT);
+ };
+}
+
+if (Prototype.Browser.IE || Prototype.Browser.Opera) {
+ // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements
+ Element.Methods.update = function(element, content) {
+ element = $(element);
+
+ if (content && content.toElement) content = content.toElement();
+ if (Object.isElement(content)) return element.update().insert(content);
+
+ content = Object.toHTML(content);
+ var tagName = element.tagName.toUpperCase();
+
+ if (tagName in Element._insertionTranslations.tags) {
+ $A(element.childNodes).each(function(node) { element.removeChild(node) });
+ Element._getContentFromAnonymousElement(tagName, content.stripScripts())
+ .each(function(node) { element.appendChild(node) });
+ }
+ else element.innerHTML = content.stripScripts();
+
+ content.evalScripts.bind(content).defer();
+ return element;
+ };
+}
+
+if (document.createElement('div').outerHTML) {
+ Element.Methods.replace = function(element, content) {
+ element = $(element);
+
+ if (content && content.toElement) content = content.toElement();
+ if (Object.isElement(content)) {
+ element.parentNode.replaceChild(content, element);
+ return element;
+ }
+
+ content = Object.toHTML(content);
+ var parent = element.parentNode, tagName = parent.tagName.toUpperCase();
+
+ if (Element._insertionTranslations.tags[tagName]) {
+ var nextSibling = element.next();
+ var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
+ parent.removeChild(element);
+ if (nextSibling)
+ fragments.each(function(node) { parent.insertBefore(node, nextSibling) });
+ else
+ fragments.each(function(node) { parent.appendChild(node) });
+ }
+ else element.outerHTML = content.stripScripts();
+
+ content.evalScripts.bind(content).defer();
+ return element;
+ };
+}
+
+Element._returnOffset = function(l, t) {
+ var result = [l, t];
+ result.left = l;
+ result.top = t;
+ return result;
+};
+
+Element._getContentFromAnonymousElement = function(tagName, html) {
+ var div = new Element('div'), t = Element._insertionTranslations.tags[tagName];
+ div.innerHTML = t[0] + html + t[1];
+ t[2].times(function() { div = div.firstChild });
+ return $A(div.childNodes);
+};
+
+Element._insertionTranslations = {
+ before: {
+ adjacency: 'beforeBegin',
+ insert: function(element, node) {
+ element.parentNode.insertBefore(node, element);
+ },
+ initializeRange: function(element, range) {
+ range.setStartBefore(element);
+ }
+ },
+ top: {
+ adjacency: 'afterBegin',
+ insert: function(element, node) {
+ element.insertBefore(node, element.firstChild);
+ },
+ initializeRange: function(element, range) {
+ range.selectNodeContents(element);
+ range.collapse(true);
+ }
+ },
+ bottom: {
+ adjacency: 'beforeEnd',
+ insert: function(element, node) {
+ element.appendChild(node);
+ }
+ },
+ after: {
+ adjacency: 'afterEnd',
+ insert: function(element, node) {
+ element.parentNode.insertBefore(node, element.nextSibling);
+ },
+ initializeRange: function(element, range) {
+ range.setStartAfter(element);
+ }
+ },
+ tags: {
+ TABLE: ['<table>', '</table>', 1],
+ TBODY: ['<table><tbody>', '</tbody></table>', 2],
+ TR: ['<table><tbody><tr>', '</tr></tbody></table>', 3],
+ TD: ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
+ SELECT: ['<select>', '</select>', 1]
+ }
+};
+
+(function() {
+ this.bottom.initializeRange = this.top.initializeRange;
+ Object.extend(this.tags, {
+ THEAD: this.tags.TBODY,
+ TFOOT: this.tags.TBODY,
+ TH: this.tags.TD
+ });
+}).call(Element._insertionTranslations);
+
+Element.Methods.Simulated = {
+ hasAttribute: function(element, attribute) {
+ attribute = Element._attributeTranslations.has[attribute] || attribute;
+ var node = $(element).getAttributeNode(attribute);
+ return node && node.specified;
+ }
+};
+
+Element.Methods.ByTag = { };
+
+Object.extend(Element, Element.Methods);
+
+if (!Prototype.BrowserFeatures.ElementExtensions &&
+ document.createElement('div').__proto__) {
+ window.HTMLElement = { };
+ window.HTMLElement.prototype = document.createElement('div').__proto__;
+ Prototype.BrowserFeatures.ElementExtensions = true;
+}
+
+Element.extend = (function() {
+ if (Prototype.BrowserFeatures.SpecificElementExtensions)
+ return Prototype.K;
+
+ var Methods = { }, ByTag = Element.Methods.ByTag;
+
+ var extend = Object.extend(function(element) {
+ if (!element || element._extendedByPrototype ||
+ element.nodeType != 1 || element == window) return element;
+
+ var methods = Object.clone(Methods),
+ tagName = element.tagName, property, value;
+
+ // extend methods for specific tags
+ if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
+
+ for (property in methods) {
+ value = methods[property];
+ if (Object.isFunction(value) && !(property in element))
+ element[property] = value.methodize();
+ }
+
+ element._extendedByPrototype = Prototype.emptyFunction;
+ return element;
+
+ }, {
+ refresh: function() {
+ // extend methods for all tags (Safari doesn't need this)
+ if (!Prototype.BrowserFeatures.ElementExtensions) {
+ Object.extend(Methods, Element.Methods);
+ Object.extend(Methods, Element.Methods.Simulated);
+ }
+ }
+ });
+
+ extend.refresh();
+ return extend;
+})();
+
+Element.hasAttribute = function(element, attribute) {
+ if (element.hasAttribute) return element.hasAttribute(attribute);
+ return Element.Methods.Simulated.hasAttribute(element, attribute);
+};
+
+Element.addMethods = function(methods) {
+ var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;
+
+ if (!methods) {
+ Object.extend(Form, Form.Methods);
+ Object.extend(Form.Element, Form.Element.Methods);
+ Object.extend(Element.Methods.ByTag, {
+ "FORM": Object.clone(Form.Methods),
+ "INPUT": Object.clone(Form.Element.Methods),
+ "SELECT": Object.clone(Form.Element.Methods),
+ "TEXTAREA": Object.clone(Form.Element.Methods)
+ });
+ }
+
+ if (arguments.length == 2) {
+ var tagName = methods;
+ methods = arguments[1];
+ }
+
+ if (!tagName) Object.extend(Element.Methods, methods || { });
+ else {
+ if (Object.isArray(tagName)) tagName.each(extend);
+ else extend(tagName);
+ }
+
+ function extend(tagName) {
+ tagName = tagName.toUpperCase();
+ if (!Element.Methods.ByTag[tagName])
+ Element.Methods.ByTag[tagName] = { };
+ Object.extend(Element.Methods.ByTag[tagName], methods);
+ }
+
+ function copy(methods, destination, onlyIfAbsent) {
+ onlyIfAbsent = onlyIfAbsent || false;
+ for (var property in methods) {
+ var value = methods[property];
+ if (!Object.isFunction(value)) continue;
+ if (!onlyIfAbsent || !(property in destination))
+ destination[property] = value.methodize();
+ }
+ }
+
+ function findDOMClass(tagName) {
+ var klass;
+ var trans = {
+ "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
+ "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
+ "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
+ "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
+ "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
+ "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
+ "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
+ "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
+ "FrameSet", "IFRAME": "IFrame"
+ };
+ if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
+ if (window[klass]) return window[klass];
+ klass = 'HTML' + tagName + 'Element';
+ if (window[klass]) return window[klass];
+ klass = 'HTML' + tagName.capitalize() + 'Element';
+ if (window[klass]) return window[klass];
+
+ window[klass] = { };
+ window[klass].prototype = document.createElement(tagName).__proto__;
+ return window[klass];
+ }
+
+ if (F.ElementExtensions) {
+ copy(Element.Methods, HTMLElement.prototype);
+ copy(Element.Methods.Simulated, HTMLElement.prototype, true);
+ }
+
+ if (F.SpecificElementExtensions) {
+ for (var tag in Element.Methods.ByTag) {
+ var klass = findDOMClass(tag);
+ if (Object.isUndefined(klass)) continue;
+ copy(T[tag], klass.prototype);
+ }
+ }
+
+ Object.extend(Element, Element.Methods);
+ delete Element.ByTag;
+
+ if (Element.extend.refresh) Element.extend.refresh();
+ Element.cache = { };
+};
+
+document.viewport = {
+ getDimensions: function() {
+ var dimensions = { };
+ var B = Prototype.Browser;
+ $w('width height').each(function(d) {
+ var D = d.capitalize();
+ dimensions[d] = (B.WebKit && !document.evaluate) ? self['inner' + D] :
+ (B.Opera) ? document.body['client' + D] : document.documentElement['client' + D];
+ });
+ return dimensions;
+ },
+
+ getWidth: function() {
+ return this.getDimensions().width;
+ },
+
+ getHeight: function() {
+ return this.getDimensions().height;
+ },
+
+ getScrollOffsets: function() {
+ return Element._returnOffset(
+ window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
+ window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
+ }
+};
+/* Portions of the Selector class are derived from Jack Slocum’s DomQuery,
+ * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
+ * license. Please see http://www.yui-ext.com/ for more information. */
+
+var Selector = Class.create({
+ initialize: function(expression) {
+ this.expression = expression.strip();
+ this.compileMatcher();
+ },
+
+ shouldUseXPath: function() {
+ if (!Prototype.BrowserFeatures.XPath) return false;
+
+ var e = this.expression;
+
+ // Safari 3 chokes on :*-of-type and :empty
+ if (Prototype.Browser.WebKit &&
+ (e.include("-of-type") || e.include(":empty")))
+ return false;
+
+ // XPath can't do namespaced attributes, nor can it read
+ // the "checked" property from DOM nodes
+ if ((/(\[[\w-]*?:|:checked)/).test(this.expression))
+ return false;
+
+ return true;
+ },
+
+ compileMatcher: function() {
+ if (this.shouldUseXPath())
+ return this.compileXPathMatcher();
+
+ var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
+ c = Selector.criteria, le, p, m;
+
+ if (Selector._cache[e]) {
+ this.matcher = Selector._cache[e];
+ return;
+ }
+
+ this.matcher = ["this.matcher = function(root) {",
+ "var r = root, h = Selector.handlers, c = false, n;"];
+
+ while (e && le != e && (/\S/).test(e)) {
+ le = e;
+ for (var i in ps) {
+ p = ps[i];
+ if (m = e.match(p)) {
+ this.matcher.push(Object.isFunction(c[i]) ? c[i](m) :
+ new Template(c[i]).evaluate(m));
+ e = e.replace(m[0], '');
+ break;
+ }
+ }
+ }
+
+ this.matcher.push("return h.unique(n);\n}");
+ eval(this.matcher.join('\n'));
+ Selector._cache[this.expression] = this.matcher;
+ },
+
+ compileXPathMatcher: function() {
+ var e = this.expression, ps = Selector.patterns,
+ x = Selector.xpath, le, m;
+
+ if (Selector._cache[e]) {
+ this.xpath = Selector._cache[e]; return;
+ }
+
+ this.matcher = ['.//*'];
+ while (e && le != e && (/\S/).test(e)) {
+ le = e;
+ for (var i in ps) {
+ if (m = e.match(ps[i])) {
+ this.matcher.push(Object.isFunction(x[i]) ? x[i](m) :
+ new Template(x[i]).evaluate(m));
+ e = e.replace(m[0], '');
+ break;
+ }
+ }
+ }
+
+ this.xpath = this.matcher.join('');
+ Selector._cache[this.expression] = this.xpath;
+ },
+
+ findElements: function(root) {
+ root = root || document;
+ if (this.xpath) return document._getElementsByXPath(this.xpath, root);
+ return this.matcher(root);
+ },
+
+ match: function(element) {
+ this.tokens = [];
+
+ var e = this.expression, ps = Selector.patterns, as = Selector.assertions;
+ var le, p, m;
+
+ while (e && le !== e && (/\S/).test(e)) {
+ le = e;
+ for (var i in ps) {
+ p = ps[i];
+ if (m = e.match(p)) {
+ // use the Selector.assertions methods unless the selector
+ // is too complex.
+ if (as[i]) {
+ this.tokens.push([i, Object.clone(m)]);
+ e = e.replace(m[0], '');
+ } else {
+ // reluctantly do a document-wide search
+ // and look for a match in the array
+ return this.findElements(document).include(element);
+ }
+ }
+ }
+ }
+
+ var match = true, name, matches;
+ for (var i = 0, token; token = this.tokens[i]; i++) {
+ name = token[0], matches = token[1];
+ if (!Selector.assertions[name](element, matches)) {
+ match = false; break;
+ }
+ }
+
+ return match;
+ },
+
+ toString: function() {
+ return this.expression;
+ },
+
+ inspect: function() {
+ return "#<Selector:" + this.expression.inspect() + ">";
+ }
+});
+
+Object.extend(Selector, {
+ _cache: { },
+
+ xpath: {
+ descendant: "//*",
+ child: "/*",
+ adjacent: "/following-sibling::*[1]",
+ laterSibling: '/following-sibling::*',
+ tagName: function(m) {
+ if (m[1] == '*') return '';
+ return "[local-name()='" + m[1].toLowerCase() +
+ "' or local-name()='" + m[1].toUpperCase() + "']";
+ },
+ className: "[contains(concat(' ', @class, ' '), ' #{1} ')]",
+ id: "[@id='#{1}']",
+ attrPresence: function(m) {
+ m[1] = m[1].toLowerCase();
+ return new Template("[@#{1}]").evaluate(m);
+ },
+ attr: function(m) {
+ m[1] = m[1].toLowerCase();
+ m[3] = m[5] || m[6];
+ return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
+ },
+ pseudo: function(m) {
+ var h = Selector.xpath.pseudos[m[1]];
+ if (!h) return '';
+ if (Object.isFunction(h)) return h(m);
+ return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
+ },
+ operators: {
+ '=': "[@#{1}='#{3}']",
+ '!=': "[@#{1}!='#{3}']",
+ '^=': "[starts-with(@#{1}, '#{3}')]",
+ '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']",
+ '*=': "[contains(@#{1}, '#{3}')]",
+ '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]",
+ '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]"
+ },
+ pseudos: {
+ 'first-child': '[not(preceding-sibling::*)]',
+ 'last-child': '[not(following-sibling::*)]',
+ 'only-child': '[not(preceding-sibling::* or following-sibling::*)]',
+ 'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",
+ 'checked': "[@checked]",
+ 'disabled': "[@disabled]",
+ 'enabled': "[not(@disabled)]",
+ 'not': function(m) {
+ var e = m[6], p = Selector.patterns,
+ x = Selector.xpath, le, v;
+
+ var exclusion = [];
+ while (e && le != e && (/\S/).test(e)) {
+ le = e;
+ for (var i in p) {
+ if (m = e.match(p[i])) {
+ v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m);
+ exclusion.push("(" + v.substring(1, v.length - 1) + ")");
+ e = e.replace(m[0], '');
+ break;
+ }
+ }
+ }
+ return "[not(" + exclusion.join(" and ") + ")]";
+ },
+ 'nth-child': function(m) {
+ return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
+ },
+ 'nth-last-child': function(m) {
+ return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);
+ },
+ 'nth-of-type': function(m) {
+ return Selector.xpath.pseudos.nth("position() ", m);
+ },
+ 'nth-last-of-type': function(m) {
+ return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);
+ },
+ 'first-of-type': function(m) {
+ m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);
+ },
+ 'last-of-type': function(m) {
+ m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);
+ },
+ 'only-of-type': function(m) {
+ var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);
+ },
+ nth: function(fragment, m) {
+ var mm, formula = m[6], predicate;
+ if (formula == 'even') formula = '2n+0';
+ if (formula == 'odd') formula = '2n+1';
+ if (mm = formula.match(/^(\d+)$/)) // digit only
+ return '[' + fragment + "= " + mm[1] + ']';
+ if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
+ if (mm[1] == "-") mm[1] = -1;
+ var a = mm[1] ? Number(mm[1]) : 1;
+ var b = mm[2] ? Number(mm[2]) : 0;
+ predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +
+ "((#{fragment} - #{b}) div #{a} >= 0)]";
+ return new Template(predicate).evaluate({
+ fragment: fragment, a: a, b: b });
+ }
+ }
+ }
+ },
+
+ criteria: {
+ tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;',
+ className: 'n = h.className(n, r, "#{1}", c); c = false;',
+ id: 'n = h.id(n, r, "#{1}", c); c = false;',
+ attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;',
+ attr: function(m) {
+ m[3] = (m[5] || m[6]);
+ return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m);
+ },
+ pseudo: function(m) {
+ if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
+ return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
+ },
+ descendant: 'c = "descendant";',
+ child: 'c = "child";',
+ adjacent: 'c = "adjacent";',
+ laterSibling: 'c = "laterSibling";'
+ },
+
+ patterns: {
+ // combinators must be listed first
+ // (and descendant needs to be last combinator)
+ laterSibling: /^\s*~\s*/,
+ child: /^\s*>\s*/,
+ adjacent: /^\s*\+\s*/,
+ descendant: /^\s/,
+
+ // selectors follow
+ tagName: /^\s*(\*|[\w\-]+)(\b|$)?/,
+ id: /^#([\w\-\*]+)(\b|$)/,
+ className: /^\.([\w\-\*]+)(\b|$)/,
+ pseudo: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s)|(?=:))/,
+ attrPresence: /^\[([\w]+)\]/,
+ attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/
+ },
+
+ // for Selector.match and Element#match
+ assertions: {
+ tagName: function(element, matches) {
+ return matches[1].toUpperCase() == element.tagName.toUpperCase();
+ },
+
+ className: function(element, matches) {
+ return Element.hasClassName(element, matches[1]);
+ },
+
+ id: function(element, matches) {
+ return element.id === matches[1];
+ },
+
+ attrPresence: function(element, matches) {
+ return Element.hasAttribute(element, matches[1]);
+ },
+
+ attr: function(element, matches) {
+ var nodeValue = Element.readAttribute(element, matches[1]);
+ return Selector.operators[matches[2]](nodeValue, matches[3]);
+ }
+ },
+
+ handlers: {
+ // UTILITY FUNCTIONS
+ // joins two collections
+ concat: function(a, b) {
+ for (var i = 0, node; node = b[i]; i++)
+ a.push(node);
+ return a;
+ },
+
+ // marks an array of nodes for counting
+ mark: function(nodes) {
+ for (var i = 0, node; node = nodes[i]; i++)
+ node._counted = true;
+ return nodes;
+ },
+
+ unmark: function(nodes) {
+ for (var i = 0, node; node = nodes[i]; i++)
+ node._counted = undefined;
+ return nodes;
+ },
+
+ // mark each child node with its position (for nth calls)
+ // "ofType" flag indicates whether we're indexing for nth-of-type
+ // rather than nth-child
+ index: function(parentNode, reverse, ofType) {
+ parentNode._counted = true;
+ if (reverse) {
+ for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
+ var node = nodes[i];
+ if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
+ }
+ } else {
+ for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
+ if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
+ }
+ },
+
+ // filters out duplicates and extends all nodes
+ unique: function(nodes) {
+ if (nodes.length == 0) return nodes;
+ var results = [], n;
+ for (var i = 0, l = nodes.length; i < l; i++)
+ if (!(n = nodes[i])._counted) {
+ n._counted = true;
+ results.push(Element.extend(n));
+ }
+ return Selector.handlers.unmark(results);
+ },
+
+ // COMBINATOR FUNCTIONS
+ descendant: function(nodes) {
+ var h = Selector.handlers;
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
+ h.concat(results, node.getElementsByTagName('*'));
+ return results;
+ },
+
+ child: function(nodes) {
+ var h = Selector.handlers;
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
+ for (var j = 0, child; child = node.childNodes[j]; j++)
+ if (child.nodeType == 1 && child.tagName != '!') results.push(child);
+ }
+ return results;
+ },
+
+ adjacent: function(nodes) {
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
+ var next = this.nextElementSibling(node);
+ if (next) results.push(next);
+ }
+ return results;
+ },
+
+ laterSibling: function(nodes) {
+ var h = Selector.handlers;
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
+ h.concat(results, Element.nextSiblings(node));
+ return results;
+ },
+
+ nextElementSibling: function(node) {
+ while (node = node.nextSibling)
+ if (node.nodeType == 1) return node;
+ return null;
+ },
+
+ previousElementSibling: function(node) {
+ while (node = node.previousSibling)
+ if (node.nodeType == 1) return node;
+ return null;
+ },
+
+ // TOKEN FUNCTIONS
+ tagName: function(nodes, root, tagName, combinator) {
+ tagName = tagName.toUpperCase();
+ var results = [], h = Selector.handlers;
+ if (nodes) {
+ if (combinator) {
+ // fastlane for ordinary descendant combinators
+ if (combinator == "descendant") {
+ for (var i = 0, node; node = nodes[i]; i++)
+ h.concat(results, node.getElementsByTagName(tagName));
+ return results;
+ } else nodes = this[combinator](nodes);
+ if (tagName == "*") return nodes;
+ }
+ for (var i = 0, node; node = nodes[i]; i++)
+ if (node.tagName.toUpperCase() == tagName) results.push(node);
+ return results;
+ } else return root.getElementsByTagName(tagName);
+ },
+
+ id: function(nodes, root, id, combinator) {
+ var targetNode = $(id), h = Selector.handlers;
+ if (!targetNode) return [];
+ if (!nodes && root == document) return [targetNode];
+ if (nodes) {
+ if (combinator) {
+ if (combinator == 'child') {
+ for (var i = 0, node; node = nodes[i]; i++)
+ if (targetNode.parentNode == node) return [targetNode];
+ } else if (combinator == 'descendant') {
+ for (var i = 0, node; node = nodes[i]; i++)
+ if (Element.descendantOf(targetNode, node)) return [targetNode];
+ } else if (combinator == 'adjacent') {
+ for (var i = 0, node; node = nodes[i]; i++)
+ if (Selector.handlers.previousElementSibling(targetNode) == node)
+ return [targetNode];
+ } else nodes = h[combinator](nodes);
+ }
+ for (var i = 0, node; node = nodes[i]; i++)
+ if (node == targetNode) return [targetNode];
+ return [];
+ }
+ return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
+ },
+
+ className: function(nodes, root, className, combinator) {
+ if (nodes && combinator) nodes = this[combinator](nodes);
+ return Selector.handlers.byClassName(nodes, root, className);
+ },
+
+ byClassName: function(nodes, root, className) {
+ if (!nodes) nodes = Selector.handlers.descendant([root]);
+ var needle = ' ' + className + ' ';
+ for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {
+ nodeClassName = node.className;
+ if (nodeClassName.length == 0) continue;
+ if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
+ results.push(node);
+ }
+ return results;
+ },
+
+ attrPresence: function(nodes, root, attr) {
+ if (!nodes) nodes = root.getElementsByTagName("*");
+ var results = [];
+ for (var i = 0, node; node = nodes[i]; i++)
+ if (Element.hasAttribute(node, attr)) results.push(node);
+ return results;
+ },
+
+ attr: function(nodes, root, attr, value, operator) {
+ if (!nodes) nodes = root.getElementsByTagName("*");
+ var handler = Selector.operators[operator], results = [];
+ for (var i = 0, node; node = nodes[i]; i++) {
+ var nodeValue = Element.readAttribute(node, attr);
+ if (nodeValue === null) continue;
+ if (handler(nodeValue, value)) results.push(node);
+ }
+ return results;
+ },
+
+ pseudo: function(nodes, name, value, root, combinator) {
+ if (nodes && combinator) nodes = this[combinator](nodes);
+ if (!nodes) nodes = root.getElementsByTagName("*");
+ return Selector.pseudos[name](nodes, value, root);
+ }
+ },
+
+ pseudos: {
+ 'first-child': function(nodes, value, root) {
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
+ if (Selector.handlers.previousElementSibling(node)) continue;
+ results.push(node);
+ }
+ return results;
+ },
+ 'last-child': function(nodes, value, root) {
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
+ if (Selector.handlers.nextElementSibling(node)) continue;
+ results.push(node);
+ }
+ return results;
+ },
+ 'only-child': function(nodes, value, root) {
+ var h = Selector.handlers;
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
+ if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
+ results.push(node);
+ return results;
+ },
+ 'nth-child': function(nodes, formula, root) {
+ return Selector.pseudos.nth(nodes, formula, root);
+ },
+ 'nth-last-child': function(nodes, formula, root) {
+ return Selector.pseudos.nth(nodes, formula, root, true);
+ },
+ 'nth-of-type': function(nodes, formula, root) {
+ return Selector.pseudos.nth(nodes, formula, root, false, true);
+ },
+ 'nth-last-of-type': function(nodes, formula, root) {
+ return Selector.pseudos.nth(nodes, formula, root, true, true);
+ },
+ 'first-of-type': function(nodes, formula, root) {
+ return Selector.pseudos.nth(nodes, "1", root, false, true);
+ },
+ 'last-of-type': function(nodes, formula, root) {
+ return Selector.pseudos.nth(nodes, "1", root, true, true);
+ },
+ 'only-of-type': function(nodes, formula, root) {
+ var p = Selector.pseudos;
+ return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
+ },
+
+ // handles the an+b logic
+ getIndices: function(a, b, total) {
+ if (a == 0) return b > 0 ? [b] : [];
+ return $R(1, total).inject([], function(memo, i) {
+ if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);
+ return memo;
+ });
+ },
+
+ // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type
+ nth: function(nodes, formula, root, reverse, ofType) {
+ if (nodes.length == 0) return [];
+ if (formula == 'even') formula = '2n+0';
+ if (formula == 'odd') formula = '2n+1';
+ var h = Selector.handlers, results = [], indexed = [], m;
+ h.mark(nodes);
+ for (var i = 0, node; node = nodes[i]; i++) {
+ if (!node.parentNode._counted) {
+ h.index(node.parentNode, reverse, ofType);
+ indexed.push(node.parentNode);
+ }
+ }
+ if (formula.match(/^\d+$/)) { // just a number
+ formula = Number(formula);
+ for (var i = 0, node; node = nodes[i]; i++)
+ if (node.nodeIndex == formula) results.push(node);
+ } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
+ if (m[1] == "-") m[1] = -1;
+ var a = m[1] ? Number(m[1]) : 1;
+ var b = m[2] ? Number(m[2]) : 0;
+ var indices = Selector.pseudos.getIndices(a, b, nodes.length);
+ for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {
+ for (var j = 0; j < l; j++)
+ if (node.nodeIndex == indices[j]) results.push(node);
+ }
+ }
+ h.unmark(nodes);
+ h.unmark(indexed);
+ return results;
+ },
+
+ 'empty': function(nodes, value, root) {
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
+ // IE treats comments as element nodes
+ if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue;
+ results.push(node);
+ }
+ return results;
+ },
+
+ 'not': function(nodes, selector, root) {
+ var h = Selector.handlers, selectorType, m;
+ var exclusions = new Selector(selector).findElements(root);
+ h.mark(exclusions);
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
+ if (!node._counted) results.push(node);
+ h.unmark(exclusions);
+ return results;
+ },
+
+ 'enabled': function(nodes, value, root) {
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
+ if (!node.disabled) results.push(node);
+ return results;
+ },
+
+ 'disabled': function(nodes, value, root) {
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
+ if (node.disabled) results.push(node);
+ return results;
+ },
+
+ 'checked': function(nodes, value, root) {
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
+ if (node.checked) results.push(node);
+ return results;
+ }
+ },
+
+ operators: {
+ '=': function(nv, v) { return nv == v; },
+ '!=': function(nv, v) { return nv != v; },
+ '^=': function(nv, v) { return nv.startsWith(v); },
+ '$=': function(nv, v) { return nv.endsWith(v); },
+ '*=': function(nv, v) { return nv.include(v); },
+ '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
+ '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
+ },
+
+ matchElements: function(elements, expression) {
+ var matches = new Selector(expression).findElements(), h = Selector.handlers;
+ h.mark(matches);
+ for (var i = 0, results = [], element; element = elements[i]; i++)
+ if (element._counted) results.push(element);
+ h.unmark(matches);
+ return results;
+ },
+
+ findElement: function(elements, expression, index) {
+ if (Object.isNumber(expression)) {
+ index = expression; expression = false;
+ }
+ return Selector.matchElements(elements, expression || '*')[index || 0];
+ },
+
+ findChildElements: function(element, expressions) {
+ var exprs = expressions.join(',');
+ expressions = [];
+ exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
+ expressions.push(m[1].strip());
+ });
+ var results = [], h = Selector.handlers;
+ for (var i = 0, l = expressions.length, selector; i < l; i++) {
+ selector = new Selector(expressions[i].strip());
+ h.concat(results, selector.findElements(element));
+ }
+ return (l > 1) ? h.unique(results) : results;
+ }
+});
+
+if (Prototype.Browser.IE) {
+ // IE returns comment nodes on getElementsByTagName("*").
+ // Filter them out.
+ Selector.handlers.concat = function(a, b) {
+ for (var i = 0, node; node = b[i]; i++)
+ if (node.tagName !== "!") a.push(node);
+ return a;
+ };
+}
+
+function $$() {
+ return Selector.findChildElements(document, $A(arguments));
+}
+var Form = {
+ reset: function(form) {
+ $(form).reset();
+ return form;
+ },
+
+ serializeElements: function(elements, options) {
+ if (typeof options != 'object') options = { hash: !!options };
+ else if (Object.isUndefined(options.hash)) options.hash = true;
+ var key, value, submitted = false, submit = options.submit;
+
+ var data = elements.inject({ }, function(result, element) {
+ if (!element.disabled && element.name) {
+ key = element.name; value = $(element).getValue();
+ if (value != null && (element.type != 'submit' || (!submitted &&
+ submit !== false && (!submit || key == submit) && (submitted = true)))) {
+ if (key in result) {
+ // a key is already present; construct an array of values
+ if (!Object.isArray(result[key])) result[key] = [result[key]];
+ result[key].push(value);
+ }
+ else result[key] = value;
+ }
+ }
+ return result;
+ });
+
+ return options.hash ? data : Object.toQueryString(data);
+ }
+};
+
+Form.Methods = {
+ serialize: function(form, options) {
+ return Form.serializeElements(Form.getElements(form), options);
+ },
+
+ getElements: function(form) {
+ return $A($(form).getElementsByTagName('*')).inject([],
+ function(elements, child) {
+ if (Form.Element.Serializers[child.tagName.toLowerCase()])
+ elements.push(Element.extend(child));
+ return elements;
+ }
+ );
+ },
+
+ getInputs: function(form, typeName, name) {
+ form = $(form);
+ var inputs = form.getElementsByTagName('input');
+
+ if (!typeName && !name) return $A(inputs).map(Element.extend);
+
+ for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
+ var input = inputs[i];
+ if ((typeName && input.type != typeName) || (name && input.name != name))
+ continue;
+ matchingInputs.push(Element.extend(input));
+ }
+
+ return matchingInputs;
+ },
+
+ disable: function(form) {
+ form = $(form);
+ Form.getElements(form).invoke('disable');
+ return form;
+ },
+
+ enable: function(form) {
+ form = $(form);
+ Form.getElements(form).invoke('enable');
+ return form;
+ },
+
+ findFirstElement: function(form) {
+ var elements = $(form).getElements().findAll(function(element) {
+ return 'hidden' != element.type && !element.disabled;
+ });
+ var firstByIndex = elements.findAll(function(element) {
+ return element.hasAttribute('tabIndex') && element.tabIndex >= 0;
+ }).sortBy(function(element) { return element.tabIndex }).first();
+
+ return firstByIndex ? firstByIndex : elements.find(function(element) {
+ return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
+ });
+ },
+
+ focusFirstElement: function(form) {
+ form = $(form);
+ form.findFirstElement().activate();
+ return form;
+ },
+
+ request: function(form, options) {
+ form = $(form), options = Object.clone(options || { });
+
+ var params = options.parameters, action = form.readAttribute('action') || '';
+ if (action.blank()) action = window.location.href;
+ options.parameters = form.serialize(true);
+
+ if (params) {
+ if (Object.isString(params)) params = params.toQueryParams();
+ Object.extend(options.parameters, params);
+ }
+
+ if (form.hasAttribute('method') && !options.method)
+ options.method = form.method;
+
+ return new Ajax.Request(action, options);
+ }
+};
+
+/*--------------------------------------------------------------------------*/
+
+Form.Element = {
+ focus: function(element) {
+ $(element).focus();
+ return element;
+ },
+
+ select: function(element) {
+ $(element).select();
+ return element;
+ }
+};
+
+Form.Element.Methods = {
+ serialize: function(element) {
+ element = $(element);
+ if (!element.disabled && element.name) {
+ var value = element.getValue();
+ if (value != undefined) {
+ var pair = { };
+ pair[element.name] = value;
+ return Object.toQueryString(pair);
+ }
+ }
+ return '';
+ },
+
+ getValue: function(element) {
+ element = $(element);
+ var method = element.tagName.toLowerCase();
+ return Form.Element.Serializers[method](element);
+ },
+
+ setValue: function(element, value) {
+ element = $(element);
+ var method = element.tagName.toLowerCase();
+ Form.Element.Serializers[method](element, value);
+ return element;
+ },
+
+ clear: function(element) {
+ $(element).value = '';
+ return element;
+ },
+
+ present: function(element) {
+ return $(element).value != '';
+ },
+
+ activate: function(element) {
+ element = $(element);
+ try {
+ element.focus();
+ if (element.select && (element.tagName.toLowerCase() != 'input' ||
+ !['button', 'reset', 'submit'].include(element.type)))
+ element.select();
+ } catch (e) { }
+ return element;
+ },
+
+ disable: function(element) {
+ element = $(element);
+ element.blur();
+ element.disabled = true;
+ return element;
+ },
+
+ enable: function(element) {
+ element = $(element);
+ element.disabled = false;
+ return element;
+ }
+};
+
+/*--------------------------------------------------------------------------*/
+
+var Field = Form.Element;
+var $F = Form.Element.Methods.getValue;
+
+/*--------------------------------------------------------------------------*/
+
+Form.Element.Serializers = {
+ input: function(element, value) {
+ switch (element.type.toLowerCase()) {
+ case 'checkbox':
+ case 'radio':
+ return Form.Element.Serializers.inputSelector(element, value);
+ default:
+ return Form.Element.Serializers.textarea(element, value);
+ }
+ },
+
+ inputSelector: function(element, value) {
+ if (Object.isUndefined(value)) return element.checked ? element.value : null;
+ else element.checked = !!value;
+ },
+
+ textarea: function(element, value) {
+ if (Object.isUndefined(value)) return element.value;
+ else element.value = value;
+ },
+
+ select: function(element, index) {
+ if (Object.isUndefined(index))
+ return this[element.type == 'select-one' ?
+ 'selectOne' : 'selectMany'](element);
+ else {
+ var opt, value, single = !Object.isArray(index);
+ for (var i = 0, length = element.length; i < length; i++) {
+ opt = element.options[i];
+ value = this.optionValue(opt);
+ if (single) {
+ if (value == index) {
+ opt.selected = true;
+ return;
+ }
+ }
+ else opt.selected = index.include(value);
+ }
+ }
+ },
+
+ selectOne: function(element) {
+ var index = element.selectedIndex;
+ return index >= 0 ? this.optionValue(element.options[index]) : null;
+ },
+
+ selectMany: function(element) {
+ var values, length = element.length;
+ if (!length) return null;
+
+ for (var i = 0, values = []; i < length; i++) {
+ var opt = element.options[i];
+ if (opt.selected) values.push(this.optionValue(opt));
+ }
+ return values;
+ },
+
+ optionValue: function(opt) {
+ // extend element because hasAttribute may not be native
+ return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
+ }
+};
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.TimedObserver = Class.create(PeriodicalExecuter, {
+ initialize: function($super, element, frequency, callback) {
+ $super(callback, frequency);
+ this.element = $(element);
+ this.lastValue = this.getValue();
+ },
+
+ execute: function() {
+ var value = this.getValue();
+ if (Object.isString(this.lastValue) && Object.isString(value) ?
+ this.lastValue != value : String(this.lastValue) != String(value)) {
+ this.callback(this.element, value);
+ this.lastValue = value;
+ }
+ }
+});
+
+Form.Element.Observer = Class.create(Abstract.TimedObserver, {
+ getValue: function() {
+ return Form.Element.getValue(this.element);
+ }
+});
+
+Form.Observer = Class.create(Abstract.TimedObserver, {
+ getValue: function() {
+ return Form.serialize(this.element);
+ }
+});
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.EventObserver = Class.create({
+ initialize: function(element, callback) {
+ this.element = $(element);
+ this.callback = callback;
+
+ this.lastValue = this.getValue();
+ if (this.element.tagName.toLowerCase() == 'form')
+ this.registerFormCallbacks();
+ else
+ this.registerCallback(this.element);
+ },
+
+ onElementEvent: function() {
+ var value = this.getValue();
+ if (this.lastValue != value) {
+ this.callback(this.element, value);
+ this.lastValue = value;
+ }
+ },
+
+ registerFormCallbacks: function() {
+ Form.getElements(this.element).each(this.registerCallback, this);
+ },
+
+ registerCallback: function(element) {
+ if (element.type) {
+ switch (element.type.toLowerCase()) {
+ case 'checkbox':
+ case 'radio':
+ Event.observe(element, 'click', this.onElementEvent.bind(this));
+ break;
+ default:
+ Event.observe(element, 'change', this.onElementEvent.bind(this));
+ break;
+ }
+ }
+ }
+});
+
+Form.Element.EventObserver = Class.create(Abstract.EventObserver, {
+ getValue: function() {
+ return Form.Element.getValue(this.element);
+ }
+});
+
+Form.EventObserver = Class.create(Abstract.EventObserver, {
+ getValue: function() {
+ return Form.serialize(this.element);
+ }
+});
+if (!window.Event) var Event = { };
+
+Object.extend(Event, {
+ KEY_BACKSPACE: 8,
+ KEY_TAB: 9,
+ KEY_RETURN: 13,
+ KEY_ESC: 27,
+ KEY_LEFT: 37,
+ KEY_UP: 38,
+ KEY_RIGHT: 39,
+ KEY_DOWN: 40,
+ KEY_DELETE: 46,
+ KEY_HOME: 36,
+ KEY_END: 35,
+ KEY_PAGEUP: 33,
+ KEY_PAGEDOWN: 34,
+ KEY_INSERT: 45,
+
+ cache: { },
+
+ relatedTarget: function(event) {
+ var element;
+ switch(event.type) {
+ case 'mouseover': element = event.fromElement; break;
+ case 'mouseout': element = event.toElement; break;
+ default: return null;
+ }
+ return Element.extend(element);
+ }
+});
+
+Event.Methods = (function() {
+ var isButton;
+
+ if (Prototype.Browser.IE) {
+ var buttonMap = { 0: 1, 1: 4, 2: 2 };
+ isButton = function(event, code) {
+ return event.button == buttonMap[code];
+ };
+
+ } else if (Prototype.Browser.WebKit) {
+ isButton = function(event, code) {
+ switch (code) {
+ case 0: return event.which == 1 && !event.metaKey;
+ case 1: return event.which == 1 && event.metaKey;
+ default: return false;
+ }
+ };
+
+ } else {
+ isButton = function(event, code) {
+ return event.which ? (event.which === code + 1) : (event.button === code);
+ };
+ }
+
+ return {
+ isLeftClick: function(event) { return isButton(event, 0) },
+ isMiddleClick: function(event) { return isButton(event, 1) },
+ isRightClick: function(event) { return isButton(event, 2) },
+
+ element: function(event) {
+ var node = Event.extend(event).target;
+ return Element.extend(node.nodeType == Node.TEXT_NODE ? node.parentNode : node);
+ },
+
+ findElement: function(event, expression) {
+ var element = Event.element(event);
+ if (!expression) return element;
+ var elements = [element].concat(element.ancestors());
+ return Selector.findElement(elements, expression, 0);
+ },
+
+ pointer: function(event) {
+ return {
+ x: event.pageX || (event.clientX +
+ (document.documentElement.scrollLeft || document.body.scrollLeft)),
+ y: event.pageY || (event.clientY +
+ (document.documentElement.scrollTop || document.body.scrollTop))
+ };
+ },
+
+ pointerX: function(event) { return Event.pointer(event).x },
+ pointerY: function(event) { return Event.pointer(event).y },
+
+ stop: function(event) {
+ Event.extend(event);
+ event.preventDefault();
+ event.stopPropagation();
+ event.stopped = true;
+ }
+ };
+})();
+
+Event.extend = (function() {
+ var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
+ m[name] = Event.Methods[name].methodize();
+ return m;
+ });
+
+ if (Prototype.Browser.IE) {
+ Object.extend(methods, {
+ stopPropagation: function() { this.cancelBubble = true },
+ preventDefault: function() { this.returnValue = false },
+ inspect: function() { return "[object Event]" }
+ });
+
+ return function(event) {
+ if (!event) return false;
+ if (event._extendedByPrototype) return event;
+
+ event._extendedByPrototype = Prototype.emptyFunction;
+ var pointer = Event.pointer(event);
+ Object.extend(event, {
+ target: event.srcElement,
+ relatedTarget: Event.relatedTarget(event),
+ pageX: pointer.x,
+ pageY: pointer.y
+ });
+ return Object.extend(event, methods);
+ };
+
+ } else {
+ Event.prototype = Event.prototype || document.createEvent("HTMLEvents").__proto__;
+ Object.extend(Event.prototype, methods);
+ return Prototype.K;
+ }
+})();
+
+Object.extend(Event, (function() {
+ var cache = Event.cache;
+
+ function getEventID(element) {
+ if (element._eventID) return element._eventID;
+ arguments.callee.id = arguments.callee.id || 1;
+ return element._eventID = ++arguments.callee.id;
+ }
+
+ function getDOMEventName(eventName) {
+ if (eventName && eventName.include(':')) return "dataavailable";
+ return eventName;
+ }
+
+ function getCacheForID(id) {
+ return cache[id] = cache[id] || { };
+ }
+
+ function getWrappersForEventName(id, eventName) {
+ var c = getCacheForID(id);
+ return c[eventName] = c[eventName] || [];
+ }
+
+ function createWrapper(element, eventName, handler) {
+ var id = getEventID(element);
+ var c = getWrappersForEventName(id, eventName);
+ if (c.pluck("handler").include(handler)) return false;
+
+ var wrapper = function(event) {
+ if (!Event || !Event.extend ||
+ (event.eventName && event.eventName != eventName))
+ return false;
+
+ Event.extend(event);
+ handler.call(element, event)
+ };
+
+ wrapper.handler = handler;
+ c.push(wrapper);
+ return wrapper;
+ }
+
+ function findWrapper(id, eventName, handler) {
+ var c = getWrappersForEventName(id, eventName);
+ return c.find(function(wrapper) { return wrapper.handler == handler });
+ }
+
+ function destroyWrapper(id, eventName, handler) {
+ var c = getCacheForID(id);
+ if (!c[eventName]) return false;
+ c[eventName] = c[eventName].without(findWrapper(id, eventName, handler));
+ }
+
+ function destroyCache() {
+ for (var id in cache)
+ for (var eventName in cache[id])
+ cache[id][eventName] = null;
+ }
+
+ if (window.attachEvent) {
+ window.attachEvent("onunload", destroyCache);
+ }
+
+ return {
+ observe: function(element, eventName, handler) {
+ element = $(element);
+ var name = getDOMEventName(eventName);
+
+ var wrapper = createWrapper(element, eventName, handler);
+ if (!wrapper) return element;
+
+ if (element.addEventListener) {
+ element.addEventListener(name, wrapper, false);
+ } else {
+ element.attachEvent("on" + name, wrapper);
+ }
+
+ return element;
+ },
+
+ stopObserving: function(element, eventName, handler) {
+ element = $(element);
+ var id = getEventID(element), name = getDOMEventName(eventName);
+
+ if (!handler && eventName) {
+ getWrappersForEventName(id, eventName).each(function(wrapper) {
+ element.stopObserving(eventName, wrapper.handler);
+ });
+ return element;
+
+ } else if (!eventName) {
+ Object.keys(getCacheForID(id)).each(function(eventName) {
+ element.stopObserving(eventName);
+ });
+ return element;
+ }
+
+ var wrapper = findWrapper(id, eventName, handler);
+ if (!wrapper) return element;
+
+ if (element.removeEventListener) {
+ element.removeEventListener(name, wrapper, false);
+ } else {
+ element.detachEvent("on" + name, wrapper);
+ }
+
+ destroyWrapper(id, eventName, handler);
+
+ return element;
+ },
+
+ fire: function(element, eventName, memo) {
+ element = $(element);
+ if (element == document && document.createEvent && !element.dispatchEvent)
+ element = document.documentElement;
+
+ if (document.createEvent) {
+ var event = document.createEvent("HTMLEvents");
+ event.initEvent("dataavailable", true, true);
+ } else {
+ var event = document.createEventObject();
+ event.eventType = "ondataavailable";
+ }
+
+ event.eventName = eventName;
+ event.memo = memo || { };
+
+ if (document.createEvent) {
+ element.dispatchEvent(event);
+ } else {
+ element.fireEvent(event.eventType, event);
+ }
+
+ return Event.extend(event);
+ }
+ };
+})());
+
+Object.extend(Event, Event.Methods);
+
+Element.addMethods({
+ fire: Event.fire,
+ observe: Event.observe,
+ stopObserving: Event.stopObserving
+});
+
+Object.extend(document, {
+ fire: Element.Methods.fire.methodize(),
+ observe: Element.Methods.observe.methodize(),
+ stopObserving: Element.Methods.stopObserving.methodize()
+});
+
+(function() {
+ /* Support for the DOMContentLoaded event is based on work by Dan Webb,
+ Matthias Miller, Dean Edwards and John Resig. */
+
+ var timer, fired = false;
+
+ function fireContentLoadedEvent() {
+ if (fired) return;
+ if (timer) window.clearInterval(timer);
+ document.fire("dom:loaded");
+ fired = true;
+ }
+
+ if (document.addEventListener) {
+ if (Prototype.Browser.WebKit) {
+ timer = window.setInterval(function() {
+ if (/loaded|complete/.test(document.readyState))
+ fireContentLoadedEvent();
+ }, 0);
+
+ Event.observe(window, "load", fireContentLoadedEvent);
+
+ } else {
+ document.addEventListener("DOMContentLoaded",
+ fireContentLoadedEvent, false);
+ }
+
+ } else {
+ document.write("<script id=__onDOMContentLoaded defer src=//:><\/script>");
+ $("__onDOMContentLoaded").onreadystatechange = function() {
+ if (this.readyState == "complete") {
+ this.onreadystatechange = null;
+ fireContentLoadedEvent();
+ }
+ };
+ }
+})();
+/*------------------------------- DEPRECATED -------------------------------*/
+
+Hash.toQueryString = Object.toQueryString;
+
+var Toggle = { display: Element.toggle };
+
+Element.Methods.childOf = Element.Methods.descendantOf;
+
+var Insertion = {
+ Before: function(element, content) {
+ return Element.insert(element, {before:content});
+ },
+
+ Top: function(element, content) {
+ return Element.insert(element, {top:content});
+ },
+
+ Bottom: function(element, content) {
+ return Element.insert(element, {bottom:content});
+ },
+
+ After: function(element, content) {
+ return Element.insert(element, {after:content});
+ }
+};
+
+var $continue = new Error('"throw $continue" is deprecated, use "return" instead');
+
+// This should be moved to script.aculo.us; notice the deprecated methods
+// further below, that map to the newer Element methods.
+var Position = {
+ // set to true if needed, warning: firefox performance problems
+ // NOT neeeded for page scrolling, only if draggable contained in
+ // scrollable elements
+ includeScrollOffsets: false,
+
+ // must be called before calling withinIncludingScrolloffset, every time the
+ // page is scrolled
+ prepare: function() {
+ this.deltaX = window.pageXOffset
+ || document.documentElement.scrollLeft
+ || document.body.scrollLeft
+ || 0;
+ this.deltaY = window.pageYOffset
+ || document.documentElement.scrollTop
+ || document.body.scrollTop
+ || 0;
+ },
+
+ // caches x/y coordinate pair to use with overlap
+ within: function(element, x, y) {
+ if (this.includeScrollOffsets)
+ return this.withinIncludingScrolloffsets(element, x, y);
+ this.xcomp = x;
+ this.ycomp = y;
+ this.offset = Element.cumulativeOffset(element);
+
+ return (y >= this.offset[1] &&
+ y < this.offset[1] + element.offsetHeight &&
+ x >= this.offset[0] &&
+ x < this.offset[0] + element.offsetWidth);
+ },
+
+ withinIncludingScrolloffsets: function(element, x, y) {
+ var offsetcache = Element.cumulativeScrollOffset(element);
+
+ this.xcomp = x + offsetcache[0] - this.deltaX;
+ this.ycomp = y + offsetcache[1] - this.deltaY;
+ this.offset = Element.cumulativeOffset(element);
+
+ return (this.ycomp >= this.offset[1] &&
+ this.ycomp < this.offset[1] + element.offsetHeight &&
+ this.xcomp >= this.offset[0] &&
+ this.xcomp < this.offset[0] + element.offsetWidth);
+ },
+
+ // within must be called directly before
+ overlap: function(mode, element) {
+ if (!mode) return 0;
+ if (mode == 'vertical')
+ return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
+ element.offsetHeight;
+ if (mode == 'horizontal')
+ return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
+ element.offsetWidth;
+ },
+
+ // Deprecation layer -- use newer Element methods now (1.5.2).
+
+ cumulativeOffset: Element.Methods.cumulativeOffset,
+
+ positionedOffset: Element.Methods.positionedOffset,
+
+ absolutize: function(element) {
+ Position.prepare();
+ return Element.absolutize(element);
+ },
+
+ relativize: function(element) {
+ Position.prepare();
+ return Element.relativize(element);
+ },
+
+ realOffset: Element.Methods.cumulativeScrollOffset,
+
+ offsetParent: Element.Methods.getOffsetParent,
+
+ page: Element.Methods.viewportOffset,
+
+ clone: function(source, target, options) {
+ options = options || { };
+ return Element.clonePosition(target, source, options);
+ }
+};
+
+/*--------------------------------------------------------------------------*/
+
+if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){
+ function iter(name) {
+ return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]";
+ }
+
+ instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?
+ function(element, className) {
+ className = className.toString().strip();
+ var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className);
+ return cond ? document._getElementsByXPath('.//*' + cond, element) : [];
+ } : function(element, className) {
+ className = className.toString().strip();
+ var elements = [], classNames = (/\s/.test(className) ? $w(className) : null);
+ if (!classNames && !className) return elements;
+
+ var nodes = $(element).getElementsByTagName('*');
+ className = ' ' + className + ' ';
+
+ for (var i = 0, child, cn; child = nodes[i]; i++) {
+ if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||
+ (classNames && classNames.all(function(name) {
+ return !name.toString().blank() && cn.include(' ' + name + ' ');
+ }))))
+ elements.push(Element.extend(child));
+ }
+ return elements;
+ };
+
+ return function(className, parentElement) {
+ return $(parentElement || document.body).getElementsByClassName(className);
+ };
+}(Element.Methods);
+
+/*--------------------------------------------------------------------------*/
+
+Element.ClassNames = Class.create();
+Element.ClassNames.prototype = {
+ initialize: function(element) {
+ this.element = $(element);
+ },
+
+ _each: function(iterator) {
+ this.element.className.split(/\s+/).select(function(name) {
+ return name.length > 0;
+ })._each(iterator);
+ },
+
+ set: function(className) {
+ this.element.className = className;
+ },
+
+ add: function(classNameToAdd) {
+ if (this.include(classNameToAdd)) return;
+ this.set($A(this).concat(classNameToAdd).join(' '));
+ },
+
+ remove: function(classNameToRemove) {
+ if (!this.include(classNameToRemove)) return;
+ this.set($A(this).without(classNameToRemove).join(' '));
+ },
+
+ toString: function() {
+ return $A(this).join(' ');
+ }
+};
+
+Object.extend(Element.ClassNames.prototype, Enumerable);
+
+/*--------------------------------------------------------------------------*/
+
+Element.addMethods(); \ No newline at end of file
diff --git a/vendor/rails-2.0.2/railties/html/robots.txt b/vendor/rails-2.0.2/railties/html/robots.txt
new file mode 100644
index 000000000..085187fa5
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/html/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/vendor/rails-2.0.2/railties/lib/code_statistics.rb b/vendor/rails-2.0.2/railties/lib/code_statistics.rb
new file mode 100644
index 000000000..740d8a176
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/code_statistics.rb
@@ -0,0 +1,107 @@
+class CodeStatistics #:nodoc:
+
+ TEST_TYPES = %w(Units Functionals Unit\ tests Functional\ tests Integration\ tests)
+
+ def initialize(*pairs)
+ @pairs = pairs
+ @statistics = calculate_statistics
+ @total = calculate_total if pairs.length > 1
+ end
+
+ def to_s
+ print_header
+ @pairs.each { |pair| print_line(pair.first, @statistics[pair.first]) }
+ print_splitter
+
+ if @total
+ print_line("Total", @total)
+ print_splitter
+ end
+
+ print_code_test_stats
+ end
+
+ private
+ def calculate_statistics
+ @pairs.inject({}) { |stats, pair| stats[pair.first] = calculate_directory_statistics(pair.last); stats }
+ end
+
+ def calculate_directory_statistics(directory, pattern = /.*\.rb$/)
+ stats = { "lines" => 0, "codelines" => 0, "classes" => 0, "methods" => 0 }
+
+ Dir.foreach(directory) do |file_name|
+ if File.stat(directory + "/" + file_name).directory? and (/^\./ !~ file_name)
+ newstats = calculate_directory_statistics(directory + "/" + file_name, pattern)
+ stats.each { |k, v| stats[k] += newstats[k] }
+ end
+
+ next unless file_name =~ pattern
+
+ f = File.open(directory + "/" + file_name)
+
+ while line = f.gets
+ stats["lines"] += 1
+ stats["classes"] += 1 if line =~ /class [A-Z]/
+ stats["methods"] += 1 if line =~ /def [a-z]/
+ stats["codelines"] += 1 unless line =~ /^\s*$/ || line =~ /^\s*#/
+ end
+ end
+
+ stats
+ end
+
+ def calculate_total
+ total = { "lines" => 0, "codelines" => 0, "classes" => 0, "methods" => 0 }
+ @statistics.each_value { |pair| pair.each { |k, v| total[k] += v } }
+ total
+ end
+
+ def calculate_code
+ code_loc = 0
+ @statistics.each { |k, v| code_loc += v['codelines'] unless TEST_TYPES.include? k }
+ code_loc
+ end
+
+ def calculate_tests
+ test_loc = 0
+ @statistics.each { |k, v| test_loc += v['codelines'] if TEST_TYPES.include? k }
+ test_loc
+ end
+
+ def print_header
+ print_splitter
+ puts "| Name | Lines | LOC | Classes | Methods | M/C | LOC/M |"
+ print_splitter
+ end
+
+ def print_splitter
+ puts "+----------------------+-------+-------+---------+---------+-----+-------+"
+ end
+
+ def print_line(name, statistics)
+ m_over_c = (statistics["methods"] / statistics["classes"]) rescue m_over_c = 0
+ loc_over_m = (statistics["codelines"] / statistics["methods"]) - 2 rescue loc_over_m = 0
+
+ start = if TEST_TYPES.include? name
+ "| #{name.ljust(20)} "
+ else
+ "| #{name.ljust(20)} "
+ end
+
+ puts start +
+ "| #{statistics["lines"].to_s.rjust(5)} " +
+ "| #{statistics["codelines"].to_s.rjust(5)} " +
+ "| #{statistics["classes"].to_s.rjust(7)} " +
+ "| #{statistics["methods"].to_s.rjust(7)} " +
+ "| #{m_over_c.to_s.rjust(3)} " +
+ "| #{loc_over_m.to_s.rjust(5)} |"
+ end
+
+ def print_code_test_stats
+ code = calculate_code
+ tests = calculate_tests
+
+ puts " Code LOC: #{code} Test LOC: #{tests} Code to Test Ratio: 1:#{sprintf("%.1f", tests.to_f/code)}"
+ puts ""
+ end
+ end
diff --git a/vendor/rails-2.0.2/railties/lib/commands.rb b/vendor/rails-2.0.2/railties/lib/commands.rb
new file mode 100644
index 000000000..841e98a0d
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/commands.rb
@@ -0,0 +1,17 @@
+commands = Dir["#{File.dirname(__FILE__)}/commands/*.rb"].collect { |file_path| File.basename(file_path).split(".").first }
+
+if commands.include?(ARGV.first)
+ require "#{File.dirname(__FILE__)}/commands/#{ARGV.shift}"
+else
+ puts <<-USAGE
+The 'run' provides a unified access point for all the default Rails' commands.
+
+Usage: ./script/run <command> [OPTIONS]
+
+Examples:
+ ./script/run generate controller Admin
+ ./script/run process reaper
+
+USAGE
+ puts "Choose: #{commands.join(", ")}"
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/railties/lib/commands/about.rb b/vendor/rails-2.0.2/railties/lib/commands/about.rb
new file mode 100644
index 000000000..313bc18c6
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/commands/about.rb
@@ -0,0 +1,2 @@
+require 'environment'
+puts Rails::Info
diff --git a/vendor/rails-2.0.2/railties/lib/commands/console.rb b/vendor/rails-2.0.2/railties/lib/commands/console.rb
new file mode 100644
index 000000000..edb135ff4
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/commands/console.rb
@@ -0,0 +1,32 @@
+irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
+
+require 'optparse'
+options = { :sandbox => false, :irb => irb }
+OptionParser.new do |opt|
+ opt.banner = "Usage: console [environment] [options]"
+ opt.on('-s', '--sandbox', 'Rollback database modifications on exit.') { |v| options[:sandbox] = v }
+ opt.on("--irb=[#{irb}]", 'Invoke a different irb.') { |v| options[:irb] = v }
+ opt.parse!(ARGV)
+end
+
+libs = " -r irb/completion"
+libs << %( -r "#{RAILS_ROOT}/config/environment")
+libs << " -r console_app"
+libs << " -r console_sandbox" if options[:sandbox]
+libs << " -r console_with_helpers"
+
+ENV['RAILS_ENV'] = case ARGV.first
+ when "p": "production"
+ when "d": "development"
+ when "t": "test"
+ else
+ ARGV.first || ENV['RAILS_ENV'] || 'development'
+end
+
+if options[:sandbox]
+ puts "Loading #{ENV['RAILS_ENV']} environment in sandbox (Rails #{Rails::VERSION::STRING})"
+ puts "Any modifications you make will be rolled back on exit"
+else
+ puts "Loading #{ENV['RAILS_ENV']} environment (Rails #{Rails::VERSION::STRING})"
+end
+exec "#{options[:irb]} #{libs} --simple-prompt"
diff --git a/vendor/rails-2.0.2/railties/lib/commands/destroy.rb b/vendor/rails-2.0.2/railties/lib/commands/destroy.rb
new file mode 100644
index 000000000..f4b81d651
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/commands/destroy.rb
@@ -0,0 +1,6 @@
+require "#{RAILS_ROOT}/config/environment"
+require 'rails_generator'
+require 'rails_generator/scripts/destroy'
+
+ARGV.shift if ['--help', '-h'].include?(ARGV[0])
+Rails::Generator::Scripts::Destroy.new.run(ARGV)
diff --git a/vendor/rails-2.0.2/railties/lib/commands/generate.rb b/vendor/rails-2.0.2/railties/lib/commands/generate.rb
new file mode 100755
index 000000000..3d3db3d85
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/commands/generate.rb
@@ -0,0 +1,6 @@
+require "#{RAILS_ROOT}/config/environment"
+require 'rails_generator'
+require 'rails_generator/scripts/generate'
+
+ARGV.shift if ['--help', '-h'].include?(ARGV[0])
+Rails::Generator::Scripts::Generate.new.run(ARGV)
diff --git a/vendor/rails-2.0.2/railties/lib/commands/ncgi/listener b/vendor/rails-2.0.2/railties/lib/commands/ncgi/listener
new file mode 100644
index 000000000..421c453f2
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/commands/ncgi/listener
@@ -0,0 +1,86 @@
+#!/usr/local/bin/ruby
+
+require 'stringio'
+require 'fileutils'
+require 'fcgi_handler'
+
+def message(s)
+ $stderr.puts "listener: #{s}" if ENV && ENV["DEBUG_GATEWAY"]
+end
+
+class RemoteCGI < CGI
+ attr_accessor :stdinput, :stdoutput, :env_table
+ def initialize(env_table, input = nil, output = nil)
+ self.env_table = env_table
+ self.stdinput = input || StringIO.new
+ self.stdoutput = output || StringIO.new
+ super()
+ end
+
+ def out(stream) # Ignore the requested output stream
+ super(stdoutput)
+ end
+end
+
+class Listener
+ include DRbUndumped
+
+ def initialize(timeout, socket_path)
+ @socket = File.expand_path(socket_path)
+ @mutex = Mutex.new
+ @active = false
+ @timeout = timeout
+
+ @handler = RailsFCGIHandler.new
+ @handler.extend DRbUndumped
+
+ message 'opening socket'
+ DRb.start_service("drbunix:#{@socket}", self)
+
+ message 'entering process loop'
+ @handler.process! self
+ end
+
+ def each_cgi(&cgi_block)
+ @cgi_block = cgi_block
+ message 'entering idle loop'
+ loop do
+ sleep @timeout rescue nil
+ die! unless @active
+ @active = false
+ end
+ end
+
+ def process(env, input)
+ message 'received request'
+ @mutex.synchronize do
+ @active = true
+
+ message 'creating input stream'
+ input_stream = StringIO.new(input)
+ message 'building CGI instance'
+ cgi = RemoteCGI.new(eval(env), input_stream)
+
+ message 'yielding to fcgi handler'
+ @cgi_block.call cgi
+ message 'yield finished -- sending output'
+
+ cgi.stdoutput.seek(0)
+ output = cgi.stdoutput.read
+
+ return output
+ end
+ end
+
+ def die!
+ message 'shutting down'
+ DRb.stop_service
+ FileUtils.rm_f @socket
+ Kernel.exit 0
+ end
+end
+
+socket_path = ARGV.shift
+timeout = (ARGV.shift || 90).to_i
+
+Listener.new(timeout, socket_path) \ No newline at end of file
diff --git a/vendor/rails-2.0.2/railties/lib/commands/ncgi/tracker b/vendor/rails-2.0.2/railties/lib/commands/ncgi/tracker
new file mode 100644
index 000000000..859c9fa0e
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/commands/ncgi/tracker
@@ -0,0 +1,69 @@
+#!/usr/local/bin/ruby
+
+require 'drb'
+require 'thread'
+
+def message(s)
+ $stderr.puts "tracker: #{s}" if ENV && ENV["DEBUG_GATEWAY"]
+end
+
+class Tracker
+ include DRbUndumped
+
+ def initialize(instances, socket_path)
+ @instances = instances
+ @socket = File.expand_path(socket_path)
+ @active = false
+
+ @listeners = []
+ @instances.times { @listeners << Mutex.new }
+
+ message "using #{@listeners.length} listeners"
+ message "opening socket at #{@socket}"
+
+ @service = DRb.start_service("drbunix://#{@socket}", self)
+ end
+
+ def with_listener
+ message "listener requested"
+
+ mutex = has_lock = index = nil
+ 3.times do
+ @listeners.each_with_index do |mutex, index|
+ has_lock = mutex.try_lock
+ break if has_lock
+ end
+ break if has_lock
+ sleep 0.05
+ end
+
+ if has_lock
+ message "obtained listener #{index}"
+ @active = true
+ begin yield index
+ ensure
+ mutex.unlock
+ message "released listener #{index}"
+ end
+ else
+ message "dropping request because no listeners are available!"
+ end
+ end
+
+ def background(check_interval = nil)
+ if check_interval
+ loop do
+ sleep check_interval
+ message "Idle for #{check_interval}, shutting down" unless @active
+ @active = false
+ Kernel.exit 0
+ end
+ else DRb.thread.join
+ end
+ end
+end
+
+socket_path = ARGV.shift
+instances = ARGV.shift.to_i
+t = Tracker.new(instances, socket_path)
+t.background(ARGV.first ? ARGV.shift.to_i : 90) \ No newline at end of file
diff --git a/vendor/rails-2.0.2/railties/lib/commands/performance/benchmarker.rb b/vendor/rails-2.0.2/railties/lib/commands/performance/benchmarker.rb
new file mode 100644
index 000000000..e8804fe1b
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/commands/performance/benchmarker.rb
@@ -0,0 +1,24 @@
+if ARGV.empty?
+ puts "Usage: ./script/performance/benchmarker [times] 'Person.expensive_way' 'Person.another_expensive_way' ..."
+ exit 1
+end
+
+begin
+ N = Integer(ARGV.first)
+ ARGV.shift
+rescue ArgumentError
+ N = 1
+end
+
+require RAILS_ROOT + '/config/environment'
+require 'benchmark'
+include Benchmark
+
+# Don't include compilation in the benchmark
+ARGV.each { |expression| eval(expression) }
+
+bm(6) do |x|
+ ARGV.each_with_index do |expression, idx|
+ x.report("##{idx + 1}") { N.times { eval(expression) } }
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/commands/performance/profiler.rb b/vendor/rails-2.0.2/railties/lib/commands/performance/profiler.rb
new file mode 100644
index 000000000..464cea344
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/commands/performance/profiler.rb
@@ -0,0 +1,50 @@
+if ARGV.empty?
+ $stderr.puts "Usage: ./script/performance/profiler 'Person.expensive_method(10)' [times] [flat|graph|graph_html]"
+ exit(1)
+end
+
+# Keep the expensive require out of the profile.
+$stderr.puts 'Loading Rails...'
+require RAILS_ROOT + '/config/environment'
+
+# Define a method to profile.
+if ARGV[1] and ARGV[1].to_i > 1
+ eval "def profile_me() #{ARGV[1]}.times { #{ARGV[0]} } end"
+else
+ eval "def profile_me() #{ARGV[0]} end"
+end
+
+# Use the ruby-prof extension if available. Fall back to stdlib profiler.
+begin
+ begin
+ require "ruby-prof"
+ $stderr.puts 'Using the ruby-prof extension.'
+ RubyProf.clock_mode = RubyProf::WALL_TIME
+ RubyProf.start
+ profile_me
+ results = RubyProf.stop
+ if ARGV[2]
+ printer_class = RubyProf.const_get((ARGV[2] + "_printer").classify)
+ else
+ printer_class = RubyProf::FlatPrinter
+ end
+ printer = printer_class.new(results)
+ printer.print($stderr, 0)
+ rescue LoadError
+ require "prof"
+ $stderr.puts 'Using the old ruby-prof extension.'
+ Prof.clock_mode = Prof::GETTIMEOFDAY
+ Prof.start
+ profile_me
+ results = Prof.stop
+ require 'rubyprof_ext'
+ Prof.print_profile(results, $stderr)
+ end
+rescue LoadError
+ require 'profiler'
+ $stderr.puts 'Using the standard Ruby profiler.'
+ Profiler__.start_profile
+ profile_me
+ Profiler__.stop_profile
+ Profiler__.print_profile($stderr)
+end
diff --git a/vendor/rails-2.0.2/railties/lib/commands/performance/request.rb b/vendor/rails-2.0.2/railties/lib/commands/performance/request.rb
new file mode 100755
index 000000000..177388648
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/commands/performance/request.rb
@@ -0,0 +1,6 @@
+#!/usr/bin/env ruby
+require 'config/environment'
+require 'application'
+require 'action_controller/request_profiler'
+
+ActionController::RequestProfiler.run(ARGV)
diff --git a/vendor/rails-2.0.2/railties/lib/commands/plugin.rb b/vendor/rails-2.0.2/railties/lib/commands/plugin.rb
new file mode 100644
index 000000000..a26f747df
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/commands/plugin.rb
@@ -0,0 +1,923 @@
+# Rails Plugin Manager.
+#
+# Listing available plugins:
+#
+# $ ./script/plugin list
+# continuous_builder http://dev.rubyonrails.com/svn/rails/plugins/continuous_builder
+# asset_timestamping http://svn.aviditybytes.com/rails/plugins/asset_timestamping
+# enumerations_mixin http://svn.protocool.com/rails/plugins/enumerations_mixin/trunk
+# calculations http://techno-weenie.net/svn/projects/calculations/
+# ...
+#
+# Installing plugins:
+#
+# $ ./script/plugin install continuous_builder asset_timestamping
+#
+# Finding Repositories:
+#
+# $ ./script/plugin discover
+#
+# Adding Repositories:
+#
+# $ ./script/plugin source http://svn.protocool.com/rails/plugins/
+#
+# How it works:
+#
+# * Maintains a list of subversion repositories that are assumed to have
+# a plugin directory structure. Manage them with the (source, unsource,
+# and sources commands)
+#
+# * The discover command scrapes the following page for things that
+# look like subversion repositories with plugins:
+# http://wiki.rubyonrails.org/rails/pages/Plugins
+#
+# * Unless you specify that you want to use svn, script/plugin uses plain old
+# HTTP for downloads. The following bullets are true if you specify
+# that you want to use svn.
+#
+# * If `vendor/plugins` is under subversion control, the script will
+# modify the svn:externals property and perform an update. You can
+# use normal subversion commands to keep the plugins up to date.
+#
+# * Or, if `vendor/plugins` is not under subversion control, the
+# plugin is pulled via `svn checkout` or `svn export` but looks
+# exactly the same.
+#
+# This is Free Software, copyright 2005 by Ryan Tomayko (rtomayko@gmail.com)
+# and is licensed MIT: (http://www.opensource.org/licenses/mit-license.php)
+
+$verbose = false
+
+
+require 'open-uri'
+require 'fileutils'
+require 'tempfile'
+
+include FileUtils
+
+class RailsEnvironment
+ attr_reader :root
+
+ def initialize(dir)
+ @root = dir
+ end
+
+ def self.find(dir=nil)
+ dir ||= pwd
+ while dir.length > 1
+ return new(dir) if File.exist?(File.join(dir, 'config', 'environment.rb'))
+ dir = File.dirname(dir)
+ end
+ end
+
+ def self.default
+ @default ||= find
+ end
+
+ def self.default=(rails_env)
+ @default = rails_env
+ end
+
+ def install(name_uri_or_plugin)
+ if name_uri_or_plugin.is_a? String
+ if name_uri_or_plugin =~ /:\/\//
+ plugin = Plugin.new(name_uri_or_plugin)
+ else
+ plugin = Plugins[name_uri_or_plugin]
+ end
+ else
+ plugin = name_uri_or_plugin
+ end
+ unless plugin.nil?
+ plugin.install
+ else
+ puts "Plugin not found: #{name_uri_or_plugin}"
+ end
+ end
+
+ def use_svn?
+ require 'active_support/core_ext/kernel'
+ silence_stderr {`svn --version` rescue nil}
+ !$?.nil? && $?.success?
+ end
+
+ def use_externals?
+ use_svn? && File.directory?("#{root}/vendor/plugins/.svn")
+ end
+
+ def use_checkout?
+ # this is a bit of a guess. we assume that if the rails environment
+ # is under subversion then they probably want the plugin checked out
+ # instead of exported. This can be overridden on the command line
+ File.directory?("#{root}/.svn")
+ end
+
+ def best_install_method
+ return :http unless use_svn?
+ case
+ when use_externals? then :externals
+ when use_checkout? then :checkout
+ else :export
+ end
+ end
+
+ def externals
+ return [] unless use_externals?
+ ext = `svn propget svn:externals "#{root}/vendor/plugins"`
+ ext.reject{ |line| line.strip == '' }.map do |line|
+ line.strip.split(/\s+/, 2)
+ end
+ end
+
+ def externals=(items)
+ unless items.is_a? String
+ items = items.map{|name,uri| "#{name.ljust(29)} #{uri.chomp('/')}"}.join("\n")
+ end
+ Tempfile.open("svn-set-prop") do |file|
+ file.write(items)
+ file.flush
+ system("svn propset -q svn:externals -F \"#{file.path}\" \"#{root}/vendor/plugins\"")
+ end
+ end
+
+end
+
+class Plugin
+ attr_reader :name, :uri
+
+ def initialize(uri, name=nil)
+ @uri = uri
+ guess_name(uri)
+ end
+
+ def self.find(name)
+ name =~ /\// ? new(name) : Repositories.instance.find_plugin(name)
+ end
+
+ def to_s
+ "#{@name.ljust(30)}#{@uri}"
+ end
+
+ def svn_url?
+ @uri =~ /svn(?:\+ssh)?:\/\/*/
+ end
+
+ def installed?
+ File.directory?("#{rails_env.root}/vendor/plugins/#{name}") \
+ or rails_env.externals.detect{ |name, repo| self.uri == repo }
+ end
+
+ def install(method=nil, options = {})
+ method ||= rails_env.best_install_method?
+ method = :export if method == :http and svn_url?
+
+ uninstall if installed? and options[:force]
+
+ unless installed?
+ send("install_using_#{method}", options)
+ run_install_hook
+ else
+ puts "already installed: #{name} (#{uri}). pass --force to reinstall"
+ end
+ end
+
+ def uninstall
+ path = "#{rails_env.root}/vendor/plugins/#{name}"
+ if File.directory?(path)
+ puts "Removing 'vendor/plugins/#{name}'" if $verbose
+ run_uninstall_hook
+ rm_r path
+ else
+ puts "Plugin doesn't exist: #{path}"
+ end
+ # clean up svn:externals
+ externals = rails_env.externals
+ externals.reject!{|n,u| name == n or name == u}
+ rails_env.externals = externals
+ end
+
+ def info
+ tmp = "#{rails_env.root}/_tmp_about.yml"
+ if svn_url?
+ cmd = "svn export #{@uri} \"#{rails_env.root}/#{tmp}\""
+ puts cmd if $verbose
+ system(cmd)
+ end
+ open(svn_url? ? tmp : File.join(@uri, 'about.yml')) do |stream|
+ stream.read
+ end rescue "No about.yml found in #{uri}"
+ ensure
+ FileUtils.rm_rf tmp if svn_url?
+ end
+
+ private
+
+ def run_install_hook
+ install_hook_file = "#{rails_env.root}/vendor/plugins/#{name}/install.rb"
+ load install_hook_file if File.exist? install_hook_file
+ end
+
+ def run_uninstall_hook
+ uninstall_hook_file = "#{rails_env.root}/vendor/plugins/#{name}/uninstall.rb"
+ load uninstall_hook_file if File.exist? uninstall_hook_file
+ end
+
+ def install_using_export(options = {})
+ svn_command :export, options
+ end
+
+ def install_using_checkout(options = {})
+ svn_command :checkout, options
+ end
+
+ def install_using_externals(options = {})
+ externals = rails_env.externals
+ externals.push([@name, uri])
+ rails_env.externals = externals
+ install_using_checkout(options)
+ end
+
+ def install_using_http(options = {})
+ root = rails_env.root
+ mkdir_p "#{root}/vendor/plugins/#{@name}"
+ Dir.chdir "#{root}/vendor/plugins/#{@name}" do
+ puts "fetching from '#{uri}'" if $verbose
+ fetcher = RecursiveHTTPFetcher.new(uri, -1)
+ fetcher.quiet = true if options[:quiet]
+ fetcher.fetch
+ end
+ end
+
+ def svn_command(cmd, options = {})
+ root = rails_env.root
+ mkdir_p "#{root}/vendor/plugins"
+ base_cmd = "svn #{cmd} #{uri} \"#{root}/vendor/plugins/#{name}\""
+ base_cmd += ' -q' if options[:quiet] and not $verbose
+ base_cmd += " -r #{options[:revision]}" if options[:revision]
+ puts base_cmd if $verbose
+ system(base_cmd)
+ end
+
+ def guess_name(url)
+ @name = File.basename(url)
+ if @name == 'trunk' || @name.empty?
+ @name = File.basename(File.dirname(url))
+ end
+ end
+
+ def rails_env
+ @rails_env || RailsEnvironment.default
+ end
+end
+
+class Repositories
+ include Enumerable
+
+ def initialize(cache_file = File.join(find_home, ".rails-plugin-sources"))
+ @cache_file = File.expand_path(cache_file)
+ load!
+ end
+
+ def each(&block)
+ @repositories.each(&block)
+ end
+
+ def add(uri)
+ unless find{|repo| repo.uri == uri }
+ @repositories.push(Repository.new(uri)).last
+ end
+ end
+
+ def remove(uri)
+ @repositories.reject!{|repo| repo.uri == uri}
+ end
+
+ def exist?(uri)
+ @repositories.detect{|repo| repo.uri == uri }
+ end
+
+ def all
+ @repositories
+ end
+
+ def find_plugin(name)
+ @repositories.each do |repo|
+ repo.each do |plugin|
+ return plugin if plugin.name == name
+ end
+ end
+ return nil
+ end
+
+ def load!
+ contents = File.exist?(@cache_file) ? File.read(@cache_file) : defaults
+ contents = defaults if contents.empty?
+ @repositories = contents.split(/\n/).reject do |line|
+ line =~ /^\s*#/ or line =~ /^\s*$/
+ end.map { |source| Repository.new(source.strip) }
+ end
+
+ def save
+ File.open(@cache_file, 'w') do |f|
+ each do |repo|
+ f.write(repo.uri)
+ f.write("\n")
+ end
+ end
+ end
+
+ def defaults
+ <<-DEFAULTS
+ http://dev.rubyonrails.com/svn/rails/plugins/
+ DEFAULTS
+ end
+
+ def find_home
+ ['HOME', 'USERPROFILE'].each do |homekey|
+ return ENV[homekey] if ENV[homekey]
+ end
+ if ENV['HOMEDRIVE'] && ENV['HOMEPATH']
+ return "#{ENV['HOMEDRIVE']}:#{ENV['HOMEPATH']}"
+ end
+ begin
+ File.expand_path("~")
+ rescue StandardError => ex
+ if File::ALT_SEPARATOR
+ "C:/"
+ else
+ "/"
+ end
+ end
+ end
+
+ def self.instance
+ @instance ||= Repositories.new
+ end
+
+ def self.each(&block)
+ self.instance.each(&block)
+ end
+end
+
+class Repository
+ include Enumerable
+ attr_reader :uri, :plugins
+
+ def initialize(uri)
+ @uri = uri.chomp('/') << "/"
+ @plugins = nil
+ end
+
+ def plugins
+ unless @plugins
+ if $verbose
+ puts "Discovering plugins in #{@uri}"
+ puts index
+ end
+
+ @plugins = index.reject{ |line| line !~ /\/$/ }
+ @plugins.map! { |name| Plugin.new(File.join(@uri, name), name) }
+ end
+
+ @plugins
+ end
+
+ def each(&block)
+ plugins.each(&block)
+ end
+
+ private
+ def index
+ @index ||= RecursiveHTTPFetcher.new(@uri).ls
+ end
+end
+
+
+# load default environment and parse arguments
+require 'optparse'
+module Commands
+
+ class Plugin
+ attr_reader :environment, :script_name, :sources
+ def initialize
+ @environment = RailsEnvironment.default
+ @rails_root = RailsEnvironment.default.root
+ @script_name = File.basename($0)
+ @sources = []
+ end
+
+ def environment=(value)
+ @environment = value
+ RailsEnvironment.default = value
+ end
+
+ def options
+ OptionParser.new do |o|
+ o.set_summary_indent(' ')
+ o.banner = "Usage: #{@script_name} [OPTIONS] command"
+ o.define_head "Rails plugin manager."
+
+ o.separator ""
+ o.separator "GENERAL OPTIONS"
+
+ o.on("-r", "--root=DIR", String,
+ "Set an explicit rails app directory.",
+ "Default: #{@rails_root}") { |@rails_root| self.environment = RailsEnvironment.new(@rails_root) }
+ o.on("-s", "--source=URL1,URL2", Array,
+ "Use the specified plugin repositories instead of the defaults.") { |@sources|}
+
+ o.on("-v", "--verbose", "Turn on verbose output.") { |$verbose| }
+ o.on("-h", "--help", "Show this help message.") { puts o; exit }
+
+ o.separator ""
+ o.separator "COMMANDS"
+
+ o.separator " discover Discover plugin repositories."
+ o.separator " list List available plugins."
+ o.separator " install Install plugin(s) from known repositories or URLs."
+ o.separator " update Update installed plugins."
+ o.separator " remove Uninstall plugins."
+ o.separator " source Add a plugin source repository."
+ o.separator " unsource Remove a plugin repository."
+ o.separator " sources List currently configured plugin repositories."
+
+ o.separator ""
+ o.separator "EXAMPLES"
+ o.separator " Install a plugin:"
+ o.separator " #{@script_name} install continuous_builder\n"
+ o.separator " Install a plugin from a subversion URL:"
+ o.separator " #{@script_name} install http://dev.rubyonrails.com/svn/rails/plugins/continuous_builder\n"
+ o.separator " Install a plugin and add a svn:externals entry to vendor/plugins"
+ o.separator " #{@script_name} install -x continuous_builder\n"
+ o.separator " List all available plugins:"
+ o.separator " #{@script_name} list\n"
+ o.separator " List plugins in the specified repository:"
+ o.separator " #{@script_name} list --source=http://dev.rubyonrails.com/svn/rails/plugins/\n"
+ o.separator " Discover and prompt to add new repositories:"
+ o.separator " #{@script_name} discover\n"
+ o.separator " Discover new repositories but just list them, don't add anything:"
+ o.separator " #{@script_name} discover -l\n"
+ o.separator " Add a new repository to the source list:"
+ o.separator " #{@script_name} source http://dev.rubyonrails.com/svn/rails/plugins/\n"
+ o.separator " Remove a repository from the source list:"
+ o.separator " #{@script_name} unsource http://dev.rubyonrails.com/svn/rails/plugins/\n"
+ o.separator " Show currently configured repositories:"
+ o.separator " #{@script_name} sources\n"
+ end
+ end
+
+ def parse!(args=ARGV)
+ general, sub = split_args(args)
+ options.parse!(general)
+
+ command = general.shift
+ if command =~ /^(list|discover|install|source|unsource|sources|remove|update|info)$/
+ command = Commands.const_get(command.capitalize).new(self)
+ command.parse!(sub)
+ else
+ puts "Unknown command: #{command}"
+ puts options
+ exit 1
+ end
+ end
+
+ def split_args(args)
+ left = []
+ left << args.shift while args[0] and args[0] =~ /^-/
+ left << args.shift if args[0]
+ return [left, args]
+ end
+
+ def self.parse!(args=ARGV)
+ Plugin.new.parse!(args)
+ end
+ end
+
+
+ class List
+ def initialize(base_command)
+ @base_command = base_command
+ @sources = []
+ @local = false
+ @remote = true
+ end
+
+ def options
+ OptionParser.new do |o|
+ o.set_summary_indent(' ')
+ o.banner = "Usage: #{@base_command.script_name} list [OPTIONS] [PATTERN]"
+ o.define_head "List available plugins."
+ o.separator ""
+ o.separator "Options:"
+ o.separator ""
+ o.on( "-s", "--source=URL1,URL2", Array,
+ "Use the specified plugin repositories.") {|@sources|}
+ o.on( "--local",
+ "List locally installed plugins.") {|@local| @remote = false}
+ o.on( "--remote",
+ "List remotely available plugins. This is the default behavior",
+ "unless --local is provided.") {|@remote|}
+ end
+ end
+
+ def parse!(args)
+ options.order!(args)
+ unless @sources.empty?
+ @sources.map!{ |uri| Repository.new(uri) }
+ else
+ @sources = Repositories.instance.all
+ end
+ if @remote
+ @sources.map{|r| r.plugins}.flatten.each do |plugin|
+ if @local or !plugin.installed?
+ puts plugin.to_s
+ end
+ end
+ else
+ cd "#{@base_command.environment.root}/vendor/plugins"
+ Dir["*"].select{|p| File.directory?(p)}.each do |name|
+ puts name
+ end
+ end
+ end
+ end
+
+
+ class Sources
+ def initialize(base_command)
+ @base_command = base_command
+ end
+
+ def options
+ OptionParser.new do |o|
+ o.set_summary_indent(' ')
+ o.banner = "Usage: #{@base_command.script_name} sources [OPTIONS] [PATTERN]"
+ o.define_head "List configured plugin repositories."
+ o.separator ""
+ o.separator "Options:"
+ o.separator ""
+ o.on( "-c", "--check",
+ "Report status of repository.") { |@sources|}
+ end
+ end
+
+ def parse!(args)
+ options.parse!(args)
+ Repositories.each do |repo|
+ puts repo.uri
+ end
+ end
+ end
+
+
+ class Source
+ def initialize(base_command)
+ @base_command = base_command
+ end
+
+ def options
+ OptionParser.new do |o|
+ o.set_summary_indent(' ')
+ o.banner = "Usage: #{@base_command.script_name} source REPOSITORY [REPOSITORY [REPOSITORY]...]"
+ o.define_head "Add new repositories to the default search list."
+ end
+ end
+
+ def parse!(args)
+ options.parse!(args)
+ count = 0
+ args.each do |uri|
+ if Repositories.instance.add(uri)
+ puts "added: #{uri.ljust(50)}" if $verbose
+ count += 1
+ else
+ puts "failed: #{uri.ljust(50)}"
+ end
+ end
+ Repositories.instance.save
+ puts "Added #{count} repositories."
+ end
+ end
+
+
+ class Unsource
+ def initialize(base_command)
+ @base_command = base_command
+ end
+
+ def options
+ OptionParser.new do |o|
+ o.set_summary_indent(' ')
+ o.banner = "Usage: #{@base_command.script_name} source URI [URI [URI]...]"
+ o.define_head "Remove repositories from the default search list."
+ o.separator ""
+ o.on_tail("-h", "--help", "Show this help message.") { puts o; exit }
+ end
+ end
+
+ def parse!(args)
+ options.parse!(args)
+ count = 0
+ args.each do |uri|
+ if Repositories.instance.remove(uri)
+ count += 1
+ puts "removed: #{uri.ljust(50)}"
+ else
+ puts "failed: #{uri.ljust(50)}"
+ end
+ end
+ Repositories.instance.save
+ puts "Removed #{count} repositories."
+ end
+ end
+
+
+ class Discover
+ def initialize(base_command)
+ @base_command = base_command
+ @list = false
+ @prompt = true
+ end
+
+ def options
+ OptionParser.new do |o|
+ o.set_summary_indent(' ')
+ o.banner = "Usage: #{@base_command.script_name} discover URI [URI [URI]...]"
+ o.define_head "Discover repositories referenced on a page."
+ o.separator ""
+ o.separator "Options:"
+ o.separator ""
+ o.on( "-l", "--list",
+ "List but don't prompt or add discovered repositories.") { |@list| @prompt = !@list }
+ o.on( "-n", "--no-prompt",
+ "Add all new repositories without prompting.") { |v| @prompt = !v }
+ end
+ end
+
+ def parse!(args)
+ options.parse!(args)
+ args = ['http://wiki.rubyonrails.org/rails/pages/Plugins'] if args.empty?
+ args.each do |uri|
+ scrape(uri) do |repo_uri|
+ catch(:next_uri) do
+ if @prompt
+ begin
+ $stdout.print "Add #{repo_uri}? [Y/n] "
+ throw :next_uri if $stdin.gets !~ /^y?$/i
+ rescue Interrupt
+ $stdout.puts
+ exit 1
+ end
+ elsif @list
+ puts repo_uri
+ throw :next_uri
+ end
+ Repositories.instance.add(repo_uri)
+ puts "discovered: #{repo_uri}" if $verbose or !@prompt
+ end
+ end
+ end
+ Repositories.instance.save
+ end
+
+ def scrape(uri)
+ require 'open-uri'
+ puts "Scraping #{uri}" if $verbose
+ dupes = []
+ content = open(uri).each do |line|
+ begin
+ if line =~ /<a[^>]*href=['"]([^'"]*)['"]/ || line =~ /(svn:\/\/[^<|\n]*)/
+ uri = $1
+ if uri =~ /^\w+:\/\// && uri =~ /\/plugins\// && uri !~ /\/browser\// && uri !~ /^http:\/\/wiki\.rubyonrails/ && uri !~ /http:\/\/instiki/
+ uri = extract_repository_uri(uri)
+ yield uri unless dupes.include?(uri) || Repositories.instance.exist?(uri)
+ dupes << uri
+ end
+ end
+ rescue
+ puts "Problems scraping '#{uri}': #{$!.to_s}"
+ end
+ end
+ end
+
+ def extract_repository_uri(uri)
+ uri.match(/(svn|https?):.*\/plugins\//i)[0]
+ end
+ end
+
+ class Install
+ def initialize(base_command)
+ @base_command = base_command
+ @method = :http
+ @options = { :quiet => false, :revision => nil, :force => false }
+ end
+
+ def options
+ OptionParser.new do |o|
+ o.set_summary_indent(' ')
+ o.banner = "Usage: #{@base_command.script_name} install PLUGIN [PLUGIN [PLUGIN] ...]"
+ o.define_head "Install one or more plugins."
+ o.separator ""
+ o.separator "Options:"
+ o.on( "-x", "--externals",
+ "Use svn:externals to grab the plugin.",
+ "Enables plugin updates and plugin versioning.") { |v| @method = :externals }
+ o.on( "-o", "--checkout",
+ "Use svn checkout to grab the plugin.",
+ "Enables updating but does not add a svn:externals entry.") { |v| @method = :checkout }
+ o.on( "-q", "--quiet",
+ "Suppresses the output from installation.",
+ "Ignored if -v is passed (./script/plugin -v install ...)") { |v| @options[:quiet] = true }
+ o.on( "-r REVISION", "--revision REVISION",
+ "Checks out the given revision from subversion.",
+ "Ignored if subversion is not used.") { |v| @options[:revision] = v }
+ o.on( "-f", "--force",
+ "Reinstalls a plugin if it's already installed.") { |v| @options[:force] = true }
+ o.separator ""
+ o.separator "You can specify plugin names as given in 'plugin list' output or absolute URLs to "
+ o.separator "a plugin repository."
+ end
+ end
+
+ def determine_install_method
+ best = @base_command.environment.best_install_method
+ @method = :http if best == :http and @method == :export
+ case
+ when (best == :http and @method != :http)
+ msg = "Cannot install using subversion because `svn' cannot be found in your PATH"
+ when (best == :export and (@method != :export and @method != :http))
+ msg = "Cannot install using #{@method} because this project is not under subversion."
+ when (best != :externals and @method == :externals)
+ msg = "Cannot install using externals because vendor/plugins is not under subversion."
+ end
+ if msg
+ puts msg
+ exit 1
+ end
+ @method
+ end
+
+ def parse!(args)
+ options.parse!(args)
+ environment = @base_command.environment
+ install_method = determine_install_method
+ puts "Plugins will be installed using #{install_method}" if $verbose
+ args.each do |name|
+ ::Plugin.find(name).install(install_method, @options)
+ end
+ rescue StandardError => e
+ puts "Plugin not found: #{args.inspect}"
+ puts e.inspect if $verbose
+ exit 1
+ end
+ end
+
+ class Update
+ def initialize(base_command)
+ @base_command = base_command
+ end
+
+ def options
+ OptionParser.new do |o|
+ o.set_summary_indent(' ')
+ o.banner = "Usage: #{@base_command.script_name} update [name [name]...]"
+ o.on( "-r REVISION", "--revision REVISION",
+ "Checks out the given revision from subversion.",
+ "Ignored if subversion is not used.") { |v| @revision = v }
+ o.define_head "Update plugins."
+ end
+ end
+
+ def parse!(args)
+ options.parse!(args)
+ root = @base_command.environment.root
+ cd root
+ args = Dir["vendor/plugins/*"].map do |f|
+ File.directory?("#{f}/.svn") ? File.basename(f) : nil
+ end.compact if args.empty?
+ cd "vendor/plugins"
+ args.each do |name|
+ if File.directory?(name)
+ puts "Updating plugin: #{name}"
+ system("svn #{$verbose ? '' : '-q'} up \"#{name}\" #{@revision ? "-r #{@revision}" : ''}")
+ else
+ puts "Plugin doesn't exist: #{name}"
+ end
+ end
+ end
+ end
+
+ class Remove
+ def initialize(base_command)
+ @base_command = base_command
+ end
+
+ def options
+ OptionParser.new do |o|
+ o.set_summary_indent(' ')
+ o.banner = "Usage: #{@base_command.script_name} remove name [name]..."
+ o.define_head "Remove plugins."
+ end
+ end
+
+ def parse!(args)
+ options.parse!(args)
+ root = @base_command.environment.root
+ args.each do |name|
+ ::Plugin.new(name).uninstall
+ end
+ end
+ end
+
+ class Info
+ def initialize(base_command)
+ @base_command = base_command
+ end
+
+ def options
+ OptionParser.new do |o|
+ o.set_summary_indent(' ')
+ o.banner = "Usage: #{@base_command.script_name} info name [name]..."
+ o.define_head "Shows plugin info at {url}/about.yml."
+ end
+ end
+
+ def parse!(args)
+ options.parse!(args)
+ args.each do |name|
+ puts ::Plugin.find(name).info
+ puts
+ end
+ end
+ end
+end
+
+class RecursiveHTTPFetcher
+ attr_accessor :quiet
+ def initialize(urls_to_fetch, level = 1, cwd = ".")
+ @level = level
+ @cwd = cwd
+ @urls_to_fetch = urls_to_fetch.to_a
+ @quiet = false
+ end
+
+ def ls
+ @urls_to_fetch.collect do |url|
+ if url =~ /^svn:\/\/.*/
+ `svn ls #{url}`.split("\n").map {|entry| "/#{entry}"} rescue nil
+ else
+ open(url) do |stream|
+ links("", stream.read)
+ end rescue nil
+ end
+ end.flatten
+ end
+
+ def push_d(dir)
+ @cwd = File.join(@cwd, dir)
+ FileUtils.mkdir_p(@cwd)
+ end
+
+ def pop_d
+ @cwd = File.dirname(@cwd)
+ end
+
+ def links(base_url, contents)
+ links = []
+ contents.scan(/href\s*=\s*\"*[^\">]*/i) do |link|
+ link = link.sub(/href="/i, "")
+ next if link =~ /svnindex.xsl$/
+ next if link =~ /^(\w*:|)\/\// || link =~ /^\./
+ links << File.join(base_url, link)
+ end
+ links
+ end
+
+ def download(link)
+ puts "+ #{File.join(@cwd, File.basename(link))}" unless @quiet
+ open(link) do |stream|
+ File.open(File.join(@cwd, File.basename(link)), "wb") do |file|
+ file.write(stream.read)
+ end
+ end
+ end
+
+ def fetch(links = @urls_to_fetch)
+ links.each do |l|
+ (l =~ /\/$/ || links == @urls_to_fetch) ? fetch_dir(l) : download(l)
+ end
+ end
+
+ def fetch_dir(url)
+ @level += 1
+ push_d(File.basename(url)) if @level > 0
+ open(url) do |stream|
+ contents = stream.read
+ fetch(links(url, contents))
+ end
+ pop_d if @level > 0
+ @level -= 1
+ end
+end
+
+Commands::Plugin.parse!
diff --git a/vendor/rails-2.0.2/railties/lib/commands/process/inspector.rb b/vendor/rails-2.0.2/railties/lib/commands/process/inspector.rb
new file mode 100644
index 000000000..8a6437e71
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/commands/process/inspector.rb
@@ -0,0 +1,68 @@
+require 'optparse'
+
+if RUBY_PLATFORM =~ /(:?mswin|mingw)/ then abort("Inspector is only for Unix") end
+
+OPTIONS = {
+ :pid_path => File.expand_path(RAILS_ROOT + '/tmp/pids'),
+ :pattern => "dispatch.*.pid",
+ :ps => "ps -o pid,state,user,start,time,pcpu,vsz,majflt,command -p %s"
+}
+
+class Inspector
+ def self.inspect(pid_path, pattern)
+ new(pid_path, pattern).inspect
+ end
+
+ def initialize(pid_path, pattern)
+ @pid_path, @pattern = pid_path, pattern
+ end
+
+ def inspect
+ header = `#{OPTIONS[:ps] % 1}`.split("\n")[0] + "\n"
+ lines = pids.collect { |pid| `#{OPTIONS[:ps] % pid}`.split("\n")[1] }
+
+ puts(header + lines.join("\n"))
+ end
+
+ private
+ def pids
+ pid_files.collect do |pid_file|
+ File.read(pid_file).to_i
+ end
+ end
+
+ def pid_files
+ Dir.glob(@pid_path + "/" + @pattern)
+ end
+end
+
+
+ARGV.options do |opts|
+ opts.banner = "Usage: inspector [options]"
+
+ opts.separator ""
+
+ opts.on <<-EOF
+ Description:
+ Displays system information about Rails dispatchers (or other processes that use pid files) through
+ the ps command.
+
+ Examples:
+ inspector # default ps on all tmp/pids/dispatch.*.pid files
+ inspector -s 'ps -o user,start,majflt,pcpu,vsz -p %s' # custom ps, %s is where the pid is interleaved
+ EOF
+
+ opts.on(" Options:")
+
+ opts.on("-s", "--ps=command", "default: #{OPTIONS[:ps]}", String) { |v| OPTIONS[:ps] = v }
+ opts.on("-p", "--pidpath=path", "default: #{OPTIONS[:pid_path]}", String) { |v| OPTIONS[:pid_path] = v }
+ opts.on("-r", "--pattern=pattern", "default: #{OPTIONS[:pattern]}", String) { |v| OPTIONS[:pattern] = v }
+
+ opts.separator ""
+
+ opts.on("-h", "--help", "Show this help message.") { puts opts; exit }
+
+ opts.parse!
+end
+
+Inspector.inspect(OPTIONS[:pid_path], OPTIONS[:pattern])
diff --git a/vendor/rails-2.0.2/railties/lib/commands/process/reaper.rb b/vendor/rails-2.0.2/railties/lib/commands/process/reaper.rb
new file mode 100644
index 000000000..95175d41e
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/commands/process/reaper.rb
@@ -0,0 +1,149 @@
+require 'optparse'
+require 'net/http'
+require 'uri'
+
+if RUBY_PLATFORM =~ /(:?mswin|mingw)/ then abort("Reaper is only for Unix") end
+
+class Killer
+ class << self
+ # Searches for all processes matching the given keywords, and then invokes
+ # a specific action on each of them. This is useful for (e.g.) reloading a
+ # set of processes:
+ #
+ # Killer.process(:reload, "/tmp/pids", "dispatcher.*.pid")
+ def process(action, pid_path, pattern, keyword)
+ new(pid_path, pattern, keyword).process(action)
+ end
+
+ # Forces the (rails) application to reload by sending a +HUP+ signal to the
+ # process.
+ def reload(pid)
+ `kill -s HUP #{pid}`
+ end
+
+ # Force the (rails) application to restart by sending a +USR2+ signal to the
+ # process.
+ def restart(pid)
+ `kill -s USR2 #{pid}`
+ end
+
+ # Forces the (rails) application to gracefully terminate by sending a
+ # +TERM+ signal to the process.
+ def graceful(pid)
+ `kill -s TERM #{pid}`
+ end
+
+ # Forces the (rails) application to terminate immediately by sending a -9
+ # signal to the process.
+ def kill(pid)
+ `kill -9 #{pid}`
+ end
+
+ # Send a +USR1+ signal to the process.
+ def usr1(pid)
+ `kill -s USR1 #{pid}`
+ end
+ end
+
+ def initialize(pid_path, pattern, keyword=nil)
+ @pid_path, @pattern, @keyword = pid_path, pattern, keyword
+ end
+
+ def process(action)
+ pids = find_processes
+
+ if pids.empty?
+ warn "Couldn't find any pid file in '#{@pid_path}' matching '#{@pattern}'"
+ warn "(also looked for processes matching #{@keyword.inspect})" if @keyword
+ else
+ pids.each do |pid|
+ puts "#{action.capitalize}ing #{pid}"
+ self.class.send(action, pid)
+ end
+
+ delete_pid_files if terminating?(action)
+ end
+ end
+
+ private
+ def terminating?(action)
+ [ "kill", "graceful" ].include?(action)
+ end
+
+ def find_processes
+ files = pid_files
+ if files.empty?
+ find_processes_via_grep
+ else
+ files.collect { |pid_file| File.read(pid_file).to_i }
+ end
+ end
+
+ def find_processes_via_grep
+ lines = `ps axww -o 'pid command' | grep #{@keyword}`.split(/\n/).
+ reject { |line| line =~ /inq|ps axww|grep|spawn-fcgi|spawner|reaper/ }
+ lines.map { |line| line[/^\s*(\d+)/, 1].to_i }
+ end
+
+ def delete_pid_files
+ pid_files.each { |pid_file| File.delete(pid_file) }
+ end
+
+ def pid_files
+ Dir.glob(@pid_path + "/" + @pattern)
+ end
+end
+
+
+OPTIONS = {
+ :action => "restart",
+ :pid_path => File.expand_path(RAILS_ROOT + '/tmp/pids'),
+ :pattern => "dispatch.[0-9]*.pid",
+ :dispatcher => File.expand_path("#{RAILS_ROOT}/public/dispatch.fcgi")
+}
+
+ARGV.options do |opts|
+ opts.banner = "Usage: reaper [options]"
+
+ opts.separator ""
+
+ opts.on <<-EOF
+ Description:
+ The reaper is used to restart, reload, gracefully exit, and forcefully exit processes
+ running a Rails Dispatcher (or any other process responding to the same signals). This
+ is commonly done when a new version of the application is available, so the existing
+ processes can be updated to use the latest code.
+
+ It uses pid files to work on the processes and by default assume them to be located
+ in RAILS_ROOT/tmp/pids.
+
+ The reaper actions are:
+
+ * restart : Restarts the application by reloading both application and framework code
+ * reload : Only reloads the application, but not the framework (like the development environment)
+ * graceful: Marks all of the processes for exit after the next request
+ * kill : Forcefully exists all processes regardless of whether they're currently serving a request
+
+ Restart is the most common and default action.
+
+ Examples:
+ reaper # restarts the default dispatchers
+ reaper -a reload # reload the default dispatchers
+ reaper -a kill -r *.pid # kill all processes that keep pids in tmp/pids
+ EOF
+
+ opts.on(" Options:")
+
+ opts.on("-a", "--action=name", "reload|graceful|kill (default: #{OPTIONS[:action]})", String) { |v| OPTIONS[:action] = v }
+ opts.on("-p", "--pidpath=path", "default: #{OPTIONS[:pid_path]}", String) { |v| OPTIONS[:pid_path] = v }
+ opts.on("-r", "--pattern=pattern", "default: #{OPTIONS[:pattern]}", String) { |v| OPTIONS[:pattern] = v }
+ opts.on("-d", "--dispatcher=path", "DEPRECATED. default: #{OPTIONS[:dispatcher]}", String) { |v| OPTIONS[:dispatcher] = v }
+
+ opts.separator ""
+
+ opts.on("-h", "--help", "Show this help message.") { puts opts; exit }
+
+ opts.parse!
+end
+
+Killer.process(OPTIONS[:action], OPTIONS[:pid_path], OPTIONS[:pattern], OPTIONS[:dispatcher])
diff --git a/vendor/rails-2.0.2/railties/lib/commands/process/spawner.rb b/vendor/rails-2.0.2/railties/lib/commands/process/spawner.rb
new file mode 100644
index 000000000..fd09daa55
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/commands/process/spawner.rb
@@ -0,0 +1,219 @@
+require 'active_support'
+require 'optparse'
+require 'socket'
+require 'fileutils'
+
+def daemonize #:nodoc:
+ exit if fork # Parent exits, child continues.
+ Process.setsid # Become session leader.
+ exit if fork # Zap session leader. See [1].
+ Dir.chdir "/" # Release old working directory.
+ File.umask 0000 # Ensure sensible umask. Adjust as needed.
+ STDIN.reopen "/dev/null" # Free file descriptors and
+ STDOUT.reopen "/dev/null", "a" # point them somewhere sensible.
+ STDERR.reopen STDOUT # STDOUT/ERR should better go to a logfile.
+end
+
+class Spawner
+ def self.record_pid(name = "#{OPTIONS[:process]}.spawner", id = Process.pid)
+ FileUtils.mkdir_p(OPTIONS[:pids])
+ File.open(File.expand_path(OPTIONS[:pids] + "/#{name}.pid"), "w+") { |f| f.write(id) }
+ end
+
+ def self.spawn_all
+ OPTIONS[:instances].times do |i|
+ port = OPTIONS[:port] + i
+ print "Checking if something is already running on #{OPTIONS[:address]}:#{port}..."
+
+ begin
+ srv = TCPServer.new(OPTIONS[:address], port)
+ srv.close
+ srv = nil
+
+ puts "NO"
+ puts "Starting dispatcher on port: #{OPTIONS[:address]}:#{port}"
+
+ FileUtils.mkdir_p(OPTIONS[:pids])
+ spawn(port)
+ rescue
+ puts "YES"
+ end
+ end
+ end
+end
+
+class FcgiSpawner < Spawner
+ def self.spawn(port)
+ cmd = "#{OPTIONS[:spawner]} -f #{OPTIONS[:dispatcher]} -p #{port} -P #{OPTIONS[:pids]}/#{OPTIONS[:process]}.#{port}.pid"
+ cmd << " -a #{OPTIONS[:address]}" if can_bind_to_custom_address?
+ system(cmd)
+ end
+
+ def self.can_bind_to_custom_address?
+ @@can_bind_to_custom_address ||= /^\s-a\s/.match `#{OPTIONS[:spawner]} -h`
+ end
+end
+
+class MongrelSpawner < Spawner
+ def self.spawn(port)
+ cmd =
+ "mongrel_rails start -d " +
+ "-a #{OPTIONS[:address]} " +
+ "-p #{port} " +
+ "-P #{OPTIONS[:pids]}/#{OPTIONS[:process]}.#{port}.pid " +
+ "-e #{OPTIONS[:environment]} " +
+ "-c #{OPTIONS[:rails_root]} " +
+ "-l #{OPTIONS[:rails_root]}/log/mongrel.log"
+
+ # Add prefix functionality to spawner's call to mongrel_rails
+ # Digging through monrel's project subversion server, the earliest
+ # Tag that has prefix implemented in the bin/mongrel_rails file
+ # is 0.3.15 which also happens to be the earilest tag listed.
+ # References: http://mongrel.rubyforge.org/svn/tags
+ if Mongrel::Const::MONGREL_VERSION.to_f >=0.3 && !OPTIONS[:prefix].nil?
+ cmd = cmd + " --prefix #{OPTIONS[:prefix]}"
+ end
+ system(cmd)
+ end
+
+ def self.can_bind_to_custom_address?
+ true
+ end
+end
+
+
+begin
+ require_library_or_gem 'fcgi'
+rescue Exception
+ # FCGI not available
+end
+
+begin
+ require_library_or_gem 'mongrel'
+rescue Exception
+ # Mongrel not available
+end
+
+server = case ARGV.first
+ when "fcgi", "mongrel"
+ ARGV.shift
+ else
+ if defined?(Mongrel)
+ "mongrel"
+ elsif RUBY_PLATFORM !~ /(:?mswin|mingw)/ && !silence_stderr { `spawn-fcgi -version` }.blank? && defined?(FCGI)
+ "fcgi"
+ end
+end
+
+case server
+ when "fcgi"
+ puts "=> Starting FCGI dispatchers"
+ spawner_class = FcgiSpawner
+ when "mongrel"
+ puts "=> Starting mongrel dispatchers"
+ spawner_class = MongrelSpawner
+ else
+ puts "Neither FCGI (spawn-fcgi) nor Mongrel was installed and available!"
+ exit(0)
+end
+
+
+
+OPTIONS = {
+ :environment => "production",
+ :spawner => '/usr/bin/env spawn-fcgi',
+ :dispatcher => File.expand_path(RELATIVE_RAILS_ROOT + '/public/dispatch.fcgi'),
+ :pids => File.expand_path(RELATIVE_RAILS_ROOT + "/tmp/pids"),
+ :rails_root => File.expand_path(RELATIVE_RAILS_ROOT),
+ :process => "dispatch",
+ :port => 8000,
+ :address => '0.0.0.0',
+ :instances => 3,
+ :repeat => nil,
+ :prefix => nil
+}
+
+ARGV.options do |opts|
+ opts.banner = "Usage: spawner [platform] [options]"
+
+ opts.separator ""
+
+ opts.on <<-EOF
+ Description:
+ The spawner is a wrapper for spawn-fcgi and mongrel that makes it
+ easier to start multiple processes running the Rails dispatcher. The
+ spawn-fcgi command is included with the lighttpd web server, but can
+ be used with both Apache and lighttpd (and any other web server
+ supporting externally managed FCGI processes). Mongrel automatically
+ ships with with mongrel_rails for starting dispatchers.
+
+ The first choice you need to make is whether to spawn the Rails
+ dispatchers as FCGI or Mongrel. By default, this spawner will prefer
+ Mongrel, so if that's installed, and no platform choice is made,
+ Mongrel is used.
+
+ Then decide a starting port (default is 8000) and the number of FCGI
+ process instances you'd like to run. So if you pick 9100 and 3
+ instances, you'll start processes on 9100, 9101, and 9102.
+
+ By setting the repeat option, you get a protection loop, which will
+ attempt to restart any FCGI processes that might have been exited or
+ outright crashed.
+
+ You can select bind address for started processes. By default these
+ listen on every interface. For single machine installations you would
+ probably want to use 127.0.0.1, hiding them form the outside world.
+
+ Examples:
+ spawner # starts instances on 8000, 8001, and 8002
+ # using Mongrel if available.
+ spawner fcgi # starts instances on 8000, 8001, and 8002
+ # using FCGI.
+ spawner mongrel -i 5 # starts instances on 8000, 8001, 8002,
+ # 8003, and 8004 using Mongrel.
+ spawner -p 9100 -i 10 # starts 10 instances counting from 9100 to
+ # 9109 using Mongrel if available.
+ spawner -p 9100 -r 5 # starts 3 instances counting from 9100 to
+ # 9102 and attempts start them every 5
+ # seconds.
+ spawner -a 127.0.0.1 # starts 3 instances binding to localhost
+ EOF
+
+ opts.on(" Options:")
+
+ opts.on("-p", "--port=number", Integer, "Starting port number (default: #{OPTIONS[:port]})") { |OPTIONS[:port]| }
+
+ if spawner_class.can_bind_to_custom_address?
+ opts.on("-a", "--address=ip", String, "Bind to IP address (default: #{OPTIONS[:address]})") { |OPTIONS[:address]| }
+ end
+
+ opts.on("-p", "--port=number", Integer, "Starting port number (default: #{OPTIONS[:port]})") { |v| OPTIONS[:port] = v }
+ opts.on("-i", "--instances=number", Integer, "Number of instances (default: #{OPTIONS[:instances]})") { |v| OPTIONS[:instances] = v }
+ opts.on("-r", "--repeat=seconds", Integer, "Repeat spawn attempts every n seconds (default: off)") { |v| OPTIONS[:repeat] = v }
+ opts.on("-e", "--environment=name", String, "test|development|production (default: #{OPTIONS[:environment]})") { |v| OPTIONS[:environment] = v }
+ opts.on("-P", "--prefix=path", String, "URL prefix for Rails app. [Used only with Mongrel > v0.3.15]: (default: #{OPTIONS[:prefix]})") { |v| OPTIONS[:prefix] = v }
+ opts.on("-n", "--process=name", String, "default: #{OPTIONS[:process]}") { |v| OPTIONS[:process] = v }
+ opts.on("-s", "--spawner=path", String, "default: #{OPTIONS[:spawner]}") { |v| OPTIONS[:spawner] = v }
+ opts.on("-d", "--dispatcher=path", String, "default: #{OPTIONS[:dispatcher]}") { |dispatcher| OPTIONS[:dispatcher] = File.expand_path(dispatcher) }
+
+ opts.separator ""
+
+ opts.on("-h", "--help", "Show this help message.") { puts opts; exit }
+
+ opts.parse!
+end
+
+ENV["RAILS_ENV"] = OPTIONS[:environment]
+
+if OPTIONS[:repeat]
+ daemonize
+ trap("TERM") { exit }
+ spawner_class.record_pid
+
+ loop do
+ spawner_class.spawn_all
+ sleep(OPTIONS[:repeat])
+ end
+else
+ spawner_class.spawn_all
+end
diff --git a/vendor/rails-2.0.2/railties/lib/commands/process/spinner.rb b/vendor/rails-2.0.2/railties/lib/commands/process/spinner.rb
new file mode 100644
index 000000000..c0b2f09a9
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/commands/process/spinner.rb
@@ -0,0 +1,57 @@
+require 'optparse'
+
+def daemonize #:nodoc:
+ exit if fork # Parent exits, child continues.
+ Process.setsid # Become session leader.
+ exit if fork # Zap session leader. See [1].
+ Dir.chdir "/" # Release old working directory.
+ File.umask 0000 # Ensure sensible umask. Adjust as needed.
+ STDIN.reopen "/dev/null" # Free file descriptors and
+ STDOUT.reopen "/dev/null", "a" # point them somewhere sensible.
+ STDERR.reopen STDOUT # STDOUT/ERR should better go to a logfile.
+end
+
+OPTIONS = {
+ :interval => 5.0,
+ :command => File.expand_path(RAILS_ROOT + '/script/process/spawner'),
+ :daemon => false
+}
+
+ARGV.options do |opts|
+ opts.banner = "Usage: spinner [options]"
+
+ opts.separator ""
+
+ opts.on <<-EOF
+ Description:
+ The spinner is a protection loop for the spawner, which will attempt to restart any FCGI processes
+ that might have been exited or outright crashed. It's a brute-force attempt that'll just try
+ to run the spawner every X number of seconds, so it does pose a light load on the server.
+
+ Examples:
+ spinner # attempts to run the spawner with default settings every second with output on the terminal
+ spinner -i 3 -d # only run the spawner every 3 seconds and detach from the terminal to become a daemon
+ spinner -c '/path/to/app/script/process/spawner -p 9000 -i 10' -d # using custom spawner
+ EOF
+
+ opts.on(" Options:")
+
+ opts.on("-c", "--command=path", String) { |v| OPTIONS[:command] = v }
+ opts.on("-i", "--interval=seconds", Float) { |v| OPTIONS[:interval] = v }
+ opts.on("-d", "--daemon") { |v| OPTIONS[:daemon] = v }
+
+ opts.separator ""
+
+ opts.on("-h", "--help", "Show this help message.") { puts opts; exit }
+
+ opts.parse!
+end
+
+daemonize if OPTIONS[:daemon]
+
+trap(OPTIONS[:daemon] ? "TERM" : "INT") { exit }
+
+loop do
+ system(OPTIONS[:command])
+ sleep(OPTIONS[:interval])
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/railties/lib/commands/runner.rb b/vendor/rails-2.0.2/railties/lib/commands/runner.rb
new file mode 100644
index 000000000..926bc2634
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/commands/runner.rb
@@ -0,0 +1,48 @@
+require 'optparse'
+
+options = { :environment => (ENV['RAILS_ENV'] || "development").dup }
+code_or_file = nil
+
+ARGV.clone.options do |opts|
+ script_name = File.basename($0)
+ opts.banner = "Usage: #{$0} [options] ('Some.ruby(code)' or a filename)"
+
+ opts.separator ""
+
+ opts.on("-e", "--environment=name", String,
+ "Specifies the environment for the runner to operate under (test/development/production).",
+ "Default: development") { |v| options[:environment] = v }
+
+ opts.separator ""
+
+ opts.on("-h", "--help",
+ "Show this help message.") { $stderr.puts opts; exit }
+
+ if RUBY_PLATFORM !~ /mswin/
+ opts.separator ""
+ opts.separator "You can also use runner as a shebang line for your scripts like this:"
+ opts.separator "-------------------------------------------------------------"
+ opts.separator "#!/usr/bin/env #{File.expand_path($0)}"
+ opts.separator ""
+ opts.separator "Product.find(:all).each { |p| p.price *= 2 ; p.save! }"
+ opts.separator "-------------------------------------------------------------"
+ end
+
+ opts.order! { |o| code_or_file ||= o } rescue retry
+end
+
+ARGV.delete(code_or_file)
+
+ENV["RAILS_ENV"] = options[:environment]
+RAILS_ENV.replace(options[:environment]) if defined?(RAILS_ENV)
+
+require RAILS_ROOT + '/config/environment'
+
+if code_or_file.nil?
+ $stderr.puts "Run '#{$0} -h' for help."
+ exit 1
+elsif File.exist?(code_or_file)
+ eval(File.read(code_or_file))
+else
+ eval(code_or_file)
+end
diff --git a/vendor/rails-2.0.2/railties/lib/commands/server.rb b/vendor/rails-2.0.2/railties/lib/commands/server.rb
new file mode 100644
index 000000000..f84db9c04
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/commands/server.rb
@@ -0,0 +1,39 @@
+require 'active_support'
+require 'fileutils'
+
+begin
+ require_library_or_gem 'fcgi'
+rescue Exception
+ # FCGI not available
+end
+
+begin
+ require_library_or_gem 'mongrel'
+rescue Exception
+ # Mongrel not available
+end
+
+server = case ARGV.first
+ when "lighttpd", "mongrel", "webrick"
+ ARGV.shift
+ else
+ if defined?(Mongrel)
+ "mongrel"
+ elsif RUBY_PLATFORM !~ /(:?mswin|mingw)/ && !silence_stderr { `lighttpd -version` }.blank? && defined?(FCGI)
+ "lighttpd"
+ else
+ "webrick"
+ end
+end
+
+case server
+ when "webrick"
+ puts "=> Booting WEBrick..."
+ when "lighttpd"
+ puts "=> Booting lighttpd (use 'script/server webrick' to force WEBrick)"
+ when "mongrel"
+ puts "=> Booting Mongrel (use 'script/server webrick' to force WEBrick)"
+end
+
+%w(cache pids sessions sockets).each { |dir_to_make| FileUtils.mkdir_p(File.join(RAILS_ROOT, 'tmp', dir_to_make)) }
+require "commands/servers/#{server}"
diff --git a/vendor/rails-2.0.2/railties/lib/commands/servers/base.rb b/vendor/rails-2.0.2/railties/lib/commands/servers/base.rb
new file mode 100644
index 000000000..23be169a8
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/commands/servers/base.rb
@@ -0,0 +1,31 @@
+def tail(log_file)
+ cursor = File.size(log_file)
+ last_checked = Time.now
+ tail_thread = Thread.new do
+ File.open(log_file, 'r') do |f|
+ loop do
+ f.seek cursor
+ if f.mtime > last_checked
+ last_checked = f.mtime
+ contents = f.read
+ cursor += contents.length
+ print contents
+ end
+ sleep 1
+ end
+ end
+ end
+ tail_thread
+end
+
+def start_debugger
+ begin
+ require_library_or_gem 'ruby-debug'
+ Debugger.start
+ Debugger.settings[:autoeval] = true if Debugger.respond_to?(:settings)
+ puts "=> Debugger enabled"
+ rescue Exception
+ puts "You need to install ruby-debug to run the server in debugging mode. With gems, use 'gem install ruby-debug'"
+ exit
+ end
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/railties/lib/commands/servers/lighttpd.rb b/vendor/rails-2.0.2/railties/lib/commands/servers/lighttpd.rb
new file mode 100644
index 000000000..07d4f9d0b
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/commands/servers/lighttpd.rb
@@ -0,0 +1,94 @@
+require 'rbconfig'
+require 'commands/servers/base'
+
+unless RUBY_PLATFORM !~ /mswin/ && !silence_stderr { `lighttpd -version` }.blank?
+ puts "PROBLEM: Lighttpd is not available on your system (or not in your path)"
+ exit 1
+end
+
+unless defined?(FCGI)
+ puts "PROBLEM: Lighttpd requires that the FCGI Ruby bindings are installed on the system"
+ exit 1
+end
+
+require 'initializer'
+configuration = Rails::Initializer.run(:initialize_logger).configuration
+default_config_file = config_file = Pathname.new("#{RAILS_ROOT}/config/lighttpd.conf").cleanpath
+
+require 'optparse'
+
+detach = false
+command_line_port = nil
+
+ARGV.options do |opt|
+ opt.on("-p", "--port=port", "Changes the server.port number in the config/lighttpd.conf") { |port| command_line_port = port }
+ opt.on('-c', "--config=#{config_file}", 'Specify a different lighttpd config file.') { |path| config_file = path }
+ opt.on('-h', '--help', 'Show this message.') { puts opt; exit 0 }
+ opt.on('-d', '-d', 'Call with -d to detach') { detach = true; puts "=> Configuration in config/lighttpd.conf" }
+ opt.parse!
+end
+
+unless File.exist?(config_file)
+ if config_file != default_config_file
+ puts "=> #{config_file} not found."
+ exit 1
+ end
+
+ require 'fileutils'
+
+ source = File.expand_path(File.join(File.dirname(__FILE__),
+ "..", "..", "..", "configs", "lighttpd.conf"))
+ puts "=> #{config_file} not found, copying from #{source}"
+
+ FileUtils.cp(source, config_file)
+end
+
+# open the config/lighttpd.conf file and add the current user defined port setting to it
+if command_line_port
+ File.open(config_file, 'r+') do |config|
+ lines = config.readlines
+
+ lines.each do |line|
+ line.gsub!(/^\s*server.port\s*=\s*(\d+)/, "server.port = #{command_line_port}")
+ end
+
+ config.rewind
+ config.print(lines)
+ config.truncate(config.pos)
+ end
+end
+
+config = IO.read(config_file)
+default_port, default_ip = 3000, '0.0.0.0'
+port = config.scan(/^\s*server.port\s*=\s*(\d+)/).first rescue default_port
+ip = config.scan(/^\s*server.bind\s*=\s*"([^"]+)"/).first rescue default_ip
+puts "=> Rails application starting on http://#{ip || default_ip}:#{port || default_port}"
+
+tail_thread = nil
+
+if !detach
+ puts "=> Call with -d to detach"
+ puts "=> Ctrl-C to shutdown server (see config/lighttpd.conf for options)"
+ detach = false
+ tail_thread = tail(configuration.log_path)
+end
+
+trap(:INT) { exit }
+
+begin
+ `rake tmp:sockets:clear` # Needed if lighttpd crashes or otherwise leaves FCGI sockets around
+ `lighttpd #{!detach ? "-D " : ""}-f #{config_file}`
+ensure
+ unless detach
+ tail_thread.kill if tail_thread
+ puts 'Exiting'
+
+ # Ensure FCGI processes are reaped
+ silence_stream(STDOUT) do
+ ARGV.replace ['-a', 'kill']
+ require 'commands/process/reaper'
+ end
+
+ `rake tmp:sockets:clear` # Remove sockets on clean shutdown
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/commands/servers/mongrel.rb b/vendor/rails-2.0.2/railties/lib/commands/servers/mongrel.rb
new file mode 100644
index 000000000..5eb14bce1
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/commands/servers/mongrel.rb
@@ -0,0 +1,69 @@
+require 'rbconfig'
+require 'commands/servers/base'
+
+unless defined?(Mongrel)
+ puts "PROBLEM: Mongrel is not available on your system (or not in your path)"
+ exit 1
+end
+
+require 'optparse'
+
+OPTIONS = {
+ :port => 3000,
+ :ip => "0.0.0.0",
+ :environment => (ENV['RAILS_ENV'] || "development").dup,
+ :detach => false,
+ :debugger => false
+}
+
+ARGV.clone.options do |opts|
+ opts.on("-p", "--port=port", Integer, "Runs Rails on the specified port.", "Default: 3000") { |v| OPTIONS[:port] = v }
+ opts.on("-b", "--binding=ip", String, "Binds Rails to the specified ip.", "Default: 0.0.0.0") { |v| OPTIONS[:ip] = v }
+ opts.on("-d", "--daemon", "Make server run as a Daemon.") { OPTIONS[:detach] = true }
+ opts.on("-u", "--debugger", "Enable ruby-debugging for the server.") { OPTIONS[:debugger] = true }
+ opts.on("-e", "--environment=name", String,
+ "Specifies the environment to run this server under (test/development/production).",
+ "Default: development") { |v| OPTIONS[:environment] = v }
+
+ opts.separator ""
+
+ opts.on("-h", "--help", "Show this help message.") { puts opts; exit }
+
+ opts.parse!
+end
+
+puts "=> Rails application starting on http://#{OPTIONS[:ip]}:#{OPTIONS[:port]}"
+
+parameters = [
+ "start",
+ "-p", OPTIONS[:port].to_s,
+ "-a", OPTIONS[:ip].to_s,
+ "-e", OPTIONS[:environment],
+ "-P", "#{RAILS_ROOT}/tmp/pids/mongrel.pid"
+]
+
+if OPTIONS[:detach]
+ `mongrel_rails #{parameters.join(" ")} -d`
+else
+ ENV["RAILS_ENV"] = OPTIONS[:environment]
+ RAILS_ENV.replace(OPTIONS[:environment]) if defined?(RAILS_ENV)
+
+ start_debugger if OPTIONS[:debugger]
+
+ require 'initializer'
+ Rails::Initializer.run(:initialize_logger)
+
+ puts "=> Call with -d to detach"
+ puts "=> Ctrl-C to shutdown server"
+ tail_thread = tail(Pathname.new("#{File.expand_path(RAILS_ROOT)}/log/#{RAILS_ENV}.log").cleanpath)
+
+ trap(:INT) { exit }
+
+ begin
+ silence_warnings { ARGV = parameters }
+ load("mongrel_rails")
+ ensure
+ tail_thread.kill if tail_thread
+ puts 'Exiting'
+ end
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/railties/lib/commands/servers/webrick.rb b/vendor/rails-2.0.2/railties/lib/commands/servers/webrick.rb
new file mode 100644
index 000000000..b95037615
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/commands/servers/webrick.rb
@@ -0,0 +1,66 @@
+require 'webrick'
+require 'optparse'
+require 'commands/servers/base'
+
+OPTIONS = {
+ :port => 3000,
+ :ip => "0.0.0.0",
+ :environment => (ENV['RAILS_ENV'] || "development").dup,
+ :server_root => File.expand_path(RAILS_ROOT + "/public/"),
+ :server_type => WEBrick::SimpleServer,
+ :charset => "UTF-8",
+ :mime_types => WEBrick::HTTPUtils::DefaultMimeTypes,
+ :debugger => false
+
+}
+
+ARGV.options do |opts|
+ script_name = File.basename($0)
+ opts.banner = "Usage: ruby #{script_name} [options]"
+
+ opts.separator ""
+
+ opts.on("-p", "--port=port", Integer,
+ "Runs Rails on the specified port.",
+ "Default: 3000") { |v| OPTIONS[:port] = v }
+ opts.on("-b", "--binding=ip", String,
+ "Binds Rails to the specified ip.",
+ "Default: 0.0.0.0") { |v| OPTIONS[:ip] = v }
+ opts.on("-e", "--environment=name", String,
+ "Specifies the environment to run this server under (test/development/production).",
+ "Default: development") { |v| OPTIONS[:environment] = v }
+ opts.on("-m", "--mime-types=filename", String,
+ "Specifies an Apache style mime.types configuration file to be used for mime types",
+ "Default: none") { |mime_types_file| OPTIONS[:mime_types] = WEBrick::HTTPUtils::load_mime_types(mime_types_file) }
+
+ opts.on("-d", "--daemon",
+ "Make Rails run as a Daemon (only works if fork is available -- meaning on *nix)."
+ ) { OPTIONS[:server_type] = WEBrick::Daemon }
+
+ opts.on("-u", "--debugger", "Enable ruby-debugging for the server.") { OPTIONS[:debugger] = true }
+
+ opts.on("-c", "--charset=charset", String,
+ "Set default charset for output.",
+ "Default: UTF-8") { |v| OPTIONS[:charset] = v }
+
+ opts.separator ""
+
+ opts.on("-h", "--help",
+ "Show this help message.") { puts opts; exit }
+
+ opts.parse!
+end
+
+start_debugger if OPTIONS[:debugger]
+
+ENV["RAILS_ENV"] = OPTIONS[:environment]
+RAILS_ENV.replace(OPTIONS[:environment]) if defined?(RAILS_ENV)
+
+require RAILS_ROOT + "/config/environment"
+require 'webrick_server'
+
+OPTIONS['working_directory'] = File.expand_path(RAILS_ROOT)
+
+puts "=> Rails application started on http://#{OPTIONS[:ip]}:#{OPTIONS[:port]}"
+puts "=> Ctrl-C to shutdown server; call with --help for options" if OPTIONS[:server_type] == WEBrick::SimpleServer
+DispatchServlet.dispatch(OPTIONS)
diff --git a/vendor/rails-2.0.2/railties/lib/commands/update.rb b/vendor/rails-2.0.2/railties/lib/commands/update.rb
new file mode 100644
index 000000000..83ef83330
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/commands/update.rb
@@ -0,0 +1,4 @@
+require "#{RAILS_ROOT}/config/environment"
+require 'rails_generator'
+require 'rails_generator/scripts/update'
+Rails::Generator::Scripts::Update.new.run(ARGV)
diff --git a/vendor/rails-2.0.2/railties/lib/console_app.rb b/vendor/rails-2.0.2/railties/lib/console_app.rb
new file mode 100644
index 000000000..c7673642e
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/console_app.rb
@@ -0,0 +1,30 @@
+require 'action_controller/integration'
+
+# work around the at_exit hook in test/unit, which kills IRB
+Test::Unit.run = true if Test::Unit.respond_to?(:run=)
+
+# reference the global "app" instance, created on demand. To recreate the
+# instance, pass a non-false value as the parameter.
+def app(create=false)
+ @app_integration_instance = nil if create
+ @app_integration_instance ||= new_session do |sess|
+ sess.host! "www.example.com"
+ end
+end
+
+# create a new session. If a block is given, the new session will be yielded
+# to the block before being returned.
+def new_session
+ session = ActionController::Integration::Session.new
+ yield session if block_given?
+ session
+end
+
+#reloads the environment
+def reload!
+ puts "Reloading..."
+ dispatcher = ActionController::Dispatcher.new($stdout)
+ dispatcher.cleanup_application(true)
+ dispatcher.prepare_application(true)
+ true
+end
diff --git a/vendor/rails-2.0.2/railties/lib/console_sandbox.rb b/vendor/rails-2.0.2/railties/lib/console_sandbox.rb
new file mode 100644
index 000000000..5d57679c4
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/console_sandbox.rb
@@ -0,0 +1,6 @@
+ActiveRecord::Base.send :increment_open_transactions
+ActiveRecord::Base.connection.begin_db_transaction
+at_exit do
+ ActiveRecord::Base.connection.rollback_db_transaction
+ ActiveRecord::Base.send :decrement_open_transactions
+end
diff --git a/vendor/rails-2.0.2/railties/lib/console_with_helpers.rb b/vendor/rails-2.0.2/railties/lib/console_with_helpers.rb
new file mode 100644
index 000000000..79018a9f7
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/console_with_helpers.rb
@@ -0,0 +1,26 @@
+class Module
+ def include_all_modules_from(parent_module)
+ parent_module.constants.each do |const|
+ mod = parent_module.const_get(const)
+ if mod.class == Module
+ send(:include, mod)
+ include_all_modules_from(mod)
+ end
+ end
+ end
+end
+
+def helper(*helper_names)
+ returning @helper_proxy ||= Object.new do |helper|
+ helper_names.each { |h| helper.extend "#{h}_helper".classify.constantize }
+ end
+end
+
+require 'application'
+
+class << helper
+ include_all_modules_from ActionView
+end
+
+@controller = ApplicationController.new
+helper :application rescue nil
diff --git a/vendor/rails-2.0.2/railties/lib/dispatcher.rb b/vendor/rails-2.0.2/railties/lib/dispatcher.rb
new file mode 100644
index 000000000..9db424f14
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/dispatcher.rb
@@ -0,0 +1,24 @@
+#--
+# Copyright (c) 2004-2007 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.
+#++
+require 'action_controller/dispatcher'
+Dispatcher = ActionController::Dispatcher
diff --git a/vendor/rails-2.0.2/railties/lib/fcgi_handler.rb b/vendor/rails-2.0.2/railties/lib/fcgi_handler.rb
new file mode 100644
index 000000000..a644161e7
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/fcgi_handler.rb
@@ -0,0 +1,223 @@
+require 'fcgi'
+require 'logger'
+require 'dispatcher'
+require 'rbconfig'
+
+class RailsFCGIHandler
+ SIGNALS = {
+ 'HUP' => :reload,
+ 'INT' => :exit_now,
+ 'TERM' => :exit_now,
+ 'USR1' => :exit,
+ 'USR2' => :restart
+ }
+ GLOBAL_SIGNALS = SIGNALS.keys - %w(USR1)
+
+ attr_reader :when_ready
+
+ attr_accessor :log_file_path
+ attr_accessor :gc_request_period
+
+
+ # Initialize and run the FastCGI instance, passing arguments through to new.
+ def self.process!(*args, &block)
+ new(*args, &block).process!
+ end
+
+ # Initialize the FastCGI instance with the path to a crash log
+ # detailing unhandled exceptions (default RAILS_ROOT/log/fastcgi.crash.log)
+ # and the number of requests to process between garbage collection runs
+ # (default nil for normal GC behavior.) Optionally, pass a block which
+ # takes this instance as an argument for further configuration.
+ def initialize(log_file_path = nil, gc_request_period = nil)
+ self.log_file_path = log_file_path || "#{RAILS_ROOT}/log/fastcgi.crash.log"
+ self.gc_request_period = gc_request_period
+
+ # Yield for additional configuration.
+ yield self if block_given?
+
+ # Safely install signal handlers.
+ install_signal_handlers
+
+ # Start error timestamp at 11 seconds ago.
+ @last_error_on = Time.now - 11
+ end
+
+ def process!(provider = FCGI)
+ mark_features!
+
+ dispatcher_log :info, 'starting'
+ process_each_request provider
+ dispatcher_log :info, 'stopping gracefully'
+
+ rescue Exception => error
+ case error
+ when SystemExit
+ dispatcher_log :info, 'stopping after explicit exit'
+ when SignalException
+ dispatcher_error error, 'stopping after unhandled signal'
+ else
+ # Retry if exceptions occur more than 10 seconds apart.
+ if Time.now - @last_error_on > 10
+ @last_error_on = Time.now
+ dispatcher_error error, 'retrying after unhandled exception'
+ retry
+ else
+ dispatcher_error error, 'stopping after unhandled exception within 10 seconds of the last'
+ end
+ end
+ end
+
+
+ protected
+ def process_each_request(provider)
+ cgi = nil
+
+ provider.each_cgi do |cgi|
+ process_request(cgi)
+
+ case when_ready
+ when :reload
+ reload!
+ when :restart
+ close_connection(cgi)
+ restart!
+ when :exit
+ close_connection(cgi)
+ break
+ end
+ end
+ rescue SignalException => signal
+ raise unless signal.message == 'SIGUSR1'
+ close_connection(cgi)
+ end
+
+ def process_request(cgi)
+ @when_ready = nil
+ gc_countdown
+
+ with_signal_handler 'USR1' do
+ begin
+ Dispatcher.dispatch(cgi)
+ rescue SignalException, SystemExit
+ raise
+ rescue Exception => error
+ dispatcher_error error, 'unhandled dispatch error'
+ end
+ end
+ end
+
+ def logger
+ @logger ||= Logger.new(@log_file_path)
+ end
+
+ def dispatcher_log(level, msg)
+ time_str = Time.now.strftime("%d/%b/%Y:%H:%M:%S")
+ logger.send(level, "[#{time_str} :: #{$$}] #{msg}")
+ rescue Exception => log_error # Logger errors
+ STDERR << "Couldn't write to #{@log_file_path.inspect}: #{msg}\n"
+ STDERR << " #{log_error.class}: #{log_error.message}\n"
+ end
+
+ def dispatcher_error(e, msg = "")
+ error_message =
+ "Dispatcher failed to catch: #{e} (#{e.class})\n" +
+ " #{e.backtrace.join("\n ")}\n#{msg}"
+ dispatcher_log(:error, error_message)
+ end
+
+ def install_signal_handlers
+ GLOBAL_SIGNALS.each { |signal| install_signal_handler(signal) }
+ end
+
+ def install_signal_handler(signal, handler = nil)
+ if SIGNALS.include?(signal) && self.class.method_defined?(name = "#{SIGNALS[signal]}_handler")
+ handler ||= method(name).to_proc
+
+ begin
+ trap(signal, handler)
+ rescue ArgumentError
+ dispatcher_log :warn, "Ignoring unsupported signal #{signal}."
+ end
+ else
+ dispatcher_log :warn, "Ignoring unsupported signal #{signal}."
+ end
+ end
+
+ def with_signal_handler(signal)
+ install_signal_handler(signal)
+ yield
+ ensure
+ install_signal_handler(signal, 'DEFAULT')
+ end
+
+ def exit_now_handler(signal)
+ dispatcher_log :info, "asked to stop immediately"
+ exit
+ end
+
+ def exit_handler(signal)
+ dispatcher_log :info, "asked to stop ASAP"
+ @when_ready = :exit
+ end
+
+ def reload_handler(signal)
+ dispatcher_log :info, "asked to reload ASAP"
+ @when_ready = :reload
+ end
+
+ def restart_handler(signal)
+ dispatcher_log :info, "asked to restart ASAP"
+ @when_ready = :restart
+ end
+
+ def restart!
+ config = ::Config::CONFIG
+ ruby = File::join(config['bindir'], config['ruby_install_name']) + config['EXEEXT']
+ command_line = [ruby, $0, ARGV].flatten.join(' ')
+
+ dispatcher_log :info, "restarted"
+
+ # close resources as they won't be closed by
+ # the OS when using exec
+ logger.close rescue nil
+ RAILS_DEFAULT_LOGGER.close rescue nil
+
+ exec(command_line)
+ end
+
+ def reload!
+ run_gc! if gc_request_period
+ restore!
+ @when_ready = nil
+ dispatcher_log :info, "reloaded"
+ end
+
+ # Make a note of $" so we can safely reload this instance.
+ def mark_features!
+ @features = $".clone
+ end
+
+ def restore!
+ $".replace @features
+ Dispatcher.reset_application!
+ ActionController::Routing::Routes.reload
+ end
+
+ def run_gc!
+ @gc_request_countdown = gc_request_period
+ GC.enable; GC.start; GC.disable
+ end
+
+ def gc_countdown
+ if gc_request_period
+ @gc_request_countdown ||= gc_request_period
+ @gc_request_countdown -= 1
+ run_gc! if @gc_request_countdown <= 0
+ end
+ end
+
+ def close_connection(cgi)
+ cgi.instance_variable_get("@request").finish if cgi
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/initializer.rb b/vendor/rails-2.0.2/railties/lib/initializer.rb
new file mode 100644
index 000000000..4b522e292
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/initializer.rb
@@ -0,0 +1,682 @@
+require 'logger'
+require 'set'
+require 'pathname'
+
+$LOAD_PATH.unshift File.dirname(__FILE__)
+require 'railties_path'
+require 'rails/version'
+require 'rails/plugin/locator'
+require 'rails/plugin/loader'
+
+
+RAILS_ENV = (ENV['RAILS_ENV'] || 'development').dup unless defined?(RAILS_ENV)
+
+module Rails
+ # The Initializer is responsible for processing the Rails configuration, such
+ # as setting the $LOAD_PATH, requiring the right frameworks, initializing
+ # logging, and more. It can be run either as a single command that'll just
+ # use the default configuration, like this:
+ #
+ # Rails::Initializer.run
+ #
+ # But normally it's more interesting to pass in a custom configuration
+ # through the block running:
+ #
+ # Rails::Initializer.run do |config|
+ # config.frameworks -= [ :action_mailer ]
+ # end
+ #
+ # This will use the default configuration options from Rails::Configuration,
+ # but allow for overwriting on select areas.
+ class Initializer
+ # The Configuration instance used by this Initializer instance.
+ attr_reader :configuration
+
+ # The set of loaded plugins.
+ attr_reader :loaded_plugins
+
+ # Runs the initializer. By default, this will invoke the #process method,
+ # which simply executes all of the initialization routines. Alternately,
+ # you can specify explicitly which initialization routine you want:
+ #
+ # Rails::Initializer.run(:set_load_path)
+ #
+ # This is useful if you only want the load path initialized, without
+ # incuring the overhead of completely loading the entire environment.
+ def self.run(command = :process, configuration = Configuration.new)
+ yield configuration if block_given?
+ initializer = new configuration
+ initializer.send(command)
+ initializer
+ end
+
+ # Create a new Initializer instance that references the given Configuration
+ # instance.
+ def initialize(configuration)
+ @configuration = configuration
+ @loaded_plugins = []
+ end
+
+ # Sequentially step through all of the available initialization routines,
+ # in order:
+ #
+ # * #check_ruby_version
+ # * #set_load_path
+ # * #require_frameworks
+ # * #set_autoload_paths
+ # * add_plugin_load_paths
+ # * #load_environment
+ # * #initialize_encoding
+ # * #initialize_database
+ # * #initialize_logger
+ # * #initialize_framework_logging
+ # * #initialize_framework_views
+ # * #initialize_dependency_mechanism
+ # * #initialize_whiny_nils
+ # * #initialize_temporary_directories
+ # * #initialize_framework_settings
+ # * #add_support_load_paths
+ # * #load_plugins
+ # * #load_observers
+ # * #initialize_routing
+ # * #after_initialize
+ # * #load_application_initializers
+ def process
+ check_ruby_version
+ set_load_path
+
+ require_frameworks
+ set_autoload_paths
+ add_plugin_load_paths
+ load_environment
+
+ initialize_encoding
+ initialize_database
+ initialize_logger
+ initialize_framework_logging
+ initialize_framework_views
+ initialize_dependency_mechanism
+ initialize_whiny_nils
+ initialize_temporary_directories
+ initialize_framework_settings
+
+ add_support_load_paths
+
+ load_plugins
+
+ # Observers are loaded after plugins in case Observers or observed models are modified by plugins.
+ load_observers
+
+ # Routing must be initialized after plugins to allow the former to extend the routes
+ initialize_routing
+
+ # the framework is now fully initialized
+ after_initialize
+
+ load_application_initializers
+ end
+
+ # Check for valid Ruby version
+ # This is done in an external file, so we can use it
+ # from the `rails` program as well without duplication.
+ def check_ruby_version
+ require 'ruby_version_check'
+ end
+
+ # Set the <tt>$LOAD_PATH</tt> based on the value of
+ # Configuration#load_paths. Duplicates are removed.
+ def set_load_path
+ load_paths = configuration.load_paths + configuration.framework_paths
+ load_paths.reverse_each { |dir| $LOAD_PATH.unshift(dir) if File.directory?(dir) }
+ $LOAD_PATH.uniq!
+ end
+
+ # Set the paths from which Rails will automatically load source files, and
+ # the load_once paths.
+ def set_autoload_paths
+ Dependencies.load_paths = configuration.load_paths.uniq
+ Dependencies.load_once_paths = configuration.load_once_paths.uniq
+
+ extra = Dependencies.load_once_paths - Dependencies.load_paths
+ unless extra.empty?
+ abort <<-end_error
+ load_once_paths must be a subset of the load_paths.
+ Extra items in load_once_paths: #{extra * ','}
+ end_error
+ end
+
+ # Freeze the arrays so future modifications will fail rather than do nothing mysteriously
+ configuration.load_once_paths.freeze
+ end
+
+ # Requires all frameworks specified by the Configuration#frameworks
+ # list. By default, all frameworks (ActiveRecord, ActiveSupport,
+ # ActionPack, ActionMailer, and ActiveResource) are loaded.
+ def require_frameworks
+ configuration.frameworks.each { |framework| require(framework.to_s) }
+ rescue LoadError => e
+ # re-raise because Mongrel would swallow it
+ raise e.to_s
+ end
+
+ # Add the load paths used by support functions such as the info controller
+ def add_support_load_paths
+ end
+
+ # Adds all load paths from plugins to the global set of load paths, so that
+ # code from plugins can be required (explicitly or automatically via Dependencies).
+ def add_plugin_load_paths
+ plugin_loader.add_plugin_load_paths
+ end
+
+ # Loads all plugins in <tt>config.plugin_paths</tt>. <tt>plugin_paths</tt>
+ # defaults to <tt>vendor/plugins</tt> but may also be set to a list of
+ # paths, such as
+ # config.plugin_paths = ["#{RAILS_ROOT}/lib/plugins", "#{RAILS_ROOT}/vendor/plugins"]
+ #
+ # In the default implementation, as each plugin discovered in <tt>plugin_paths</tt> is initialized:
+ # * its +lib+ directory, if present, is added to the load path (immediately after the applications lib directory)
+ # * <tt>init.rb</tt> is evaluated, if present
+ #
+ # After all plugins are loaded, duplicates are removed from the load path.
+ # If an array of plugin names is specified in config.plugins, only those plugins will be loaded
+ # and they plugins will be loaded in that order. Otherwise, plugins are loaded in alphabetical
+ # order.
+ #
+ # if config.plugins ends contains :all then the named plugins will be loaded in the given order and all other
+ # plugins will be loaded in alphabetical order
+ def load_plugins
+ plugin_loader.load_plugins
+ end
+
+ def plugin_loader
+ @plugin_loader ||= configuration.plugin_loader.new(self)
+ end
+
+ # Loads the environment specified by Configuration#environment_path, which
+ # is typically one of development, test, or production.
+ def load_environment
+ silence_warnings do
+ return if @environment_loaded
+ @environment_loaded = true
+
+ config = configuration
+ constants = self.class.constants
+
+ eval(IO.read(configuration.environment_path), binding, configuration.environment_path)
+
+ (self.class.constants - constants).each do |const|
+ Object.const_set(const, self.class.const_get(const))
+ end
+ end
+ end
+
+ def load_observers
+ if configuration.frameworks.include?(:active_record)
+ ActiveRecord::Base.instantiate_observers
+ end
+ end
+
+ # This initialization sets $KCODE to 'u' to enable the multibyte safe operations.
+ # Plugin authors supporting other encodings should override this behaviour and
+ # set the relevant +default_charset+ on ActionController::Base
+ def initialize_encoding
+ $KCODE='u'
+ end
+
+ # This initialization routine does nothing unless <tt>:active_record</tt>
+ # is one of the frameworks to load (Configuration#frameworks). If it is,
+ # this sets the database configuration from Configuration#database_configuration
+ # and then establishes the connection.
+ def initialize_database
+ if configuration.frameworks.include?(:active_record)
+ ActiveRecord::Base.configurations = configuration.database_configuration
+ ActiveRecord::Base.establish_connection
+ end
+ end
+
+ # If the +RAILS_DEFAULT_LOGGER+ constant is already set, this initialization
+ # routine does nothing. If the constant is not set, and Configuration#logger
+ # is not +nil+, this also does nothing. Otherwise, a new logger instance
+ # is created at Configuration#log_path, with a default log level of
+ # Configuration#log_level.
+ #
+ # If the log could not be created, the log will be set to output to
+ # +STDERR+, with a log level of +WARN+.
+ def initialize_logger
+ # if the environment has explicitly defined a logger, use it
+ return if defined?(RAILS_DEFAULT_LOGGER)
+
+ unless logger = configuration.logger
+ begin
+ logger = ActiveSupport::BufferedLogger.new(configuration.log_path)
+ logger.level = ActiveSupport::BufferedLogger.const_get(configuration.log_level.to_s.upcase)
+ logger.auto_flushing = false if configuration.environment == "production"
+ rescue StandardError =>e
+ logger = ActiveSupport::BufferedLogger.new(STDERR)
+ logger.level = ActiveSupport::BufferedLogger::WARN
+ logger.warn(
+ "Rails Error: Unable to access log file. Please ensure that #{configuration.log_path} exists and is chmod 0666. " +
+ "The log level has been raised to WARN and the output directed to STDERR until the problem is fixed."
+ )
+ end
+ end
+
+ silence_warnings { Object.const_set "RAILS_DEFAULT_LOGGER", logger }
+ end
+
+ # Sets the logger for ActiveRecord, ActionController, and ActionMailer
+ # (but only for those frameworks that are to be loaded). If the framework's
+ # logger is already set, it is not changed, otherwise it is set to use
+ # +RAILS_DEFAULT_LOGGER+.
+ def initialize_framework_logging
+ for framework in ([ :active_record, :action_controller, :action_mailer ] & configuration.frameworks)
+ framework.to_s.camelize.constantize.const_get("Base").logger ||= RAILS_DEFAULT_LOGGER
+ end
+ end
+
+ # Sets +ActionController::Base#view_paths+ and +ActionMailer::Base#template_root+
+ # (but only for those frameworks that are to be loaded). If the framework's
+ # paths have already been set, it is not changed, otherwise it is
+ # set to use Configuration#view_path.
+ def initialize_framework_views
+ ActionMailer::Base.template_root ||= configuration.view_path if configuration.frameworks.include?(:action_mailer)
+ ActionController::Base.view_paths = [configuration.view_path] if configuration.frameworks.include?(:action_controller) && ActionController::Base.view_paths.empty?
+ end
+
+ # If ActionController is not one of the loaded frameworks (Configuration#frameworks)
+ # this does nothing. Otherwise, it loads the routing definitions and sets up
+ # loading module used to lazily load controllers (Configuration#controller_paths).
+ def initialize_routing
+ return unless configuration.frameworks.include?(:action_controller)
+ ActionController::Routing.controller_paths = configuration.controller_paths
+ ActionController::Routing::Routes.reload
+ end
+
+ # Sets the dependency loading mechanism based on the value of
+ # Configuration#cache_classes.
+ def initialize_dependency_mechanism
+ Dependencies.mechanism = configuration.cache_classes ? :require : :load
+ end
+
+ # Loads support for "whiny nil" (noisy warnings when methods are invoked
+ # on +nil+ values) if Configuration#whiny_nils is true.
+ def initialize_whiny_nils
+ require('active_support/whiny_nil') if configuration.whiny_nils
+ end
+
+ def initialize_temporary_directories
+ if configuration.frameworks.include?(:action_controller)
+ session_path = "#{configuration.root_path}/tmp/sessions/"
+ ActionController::Base.session_options[:tmpdir] = File.exist?(session_path) ? session_path : Dir::tmpdir
+
+ cache_path = "#{configuration.root_path}/tmp/cache/"
+ if File.exist?(cache_path)
+ ActionController::Base.fragment_cache_store = :file_store, cache_path
+ end
+ end
+ end
+
+ # Initializes framework-specific settings for each of the loaded frameworks
+ # (Configuration#frameworks). The available settings map to the accessors
+ # on each of the corresponding Base classes.
+ def initialize_framework_settings
+ configuration.frameworks.each do |framework|
+ base_class = framework.to_s.camelize.constantize.const_get("Base")
+
+ configuration.send(framework).each do |setting, value|
+ base_class.send("#{setting}=", value)
+ end
+ end
+ end
+
+ # Fires the user-supplied after_initialize block (Configuration#after_initialize)
+ def after_initialize
+ configuration.after_initialize_blocks.each do |block|
+ block.call
+ end
+ end
+
+ def load_application_initializers
+ Dir["#{configuration.root_path}/config/initializers/**/*.rb"].sort.each do |initializer|
+ load(initializer)
+ end
+ end
+
+ end
+
+ # The Configuration class holds all the parameters for the Initializer and
+ # ships with defaults that suites most Rails applications. But it's possible
+ # to overwrite everything. Usually, you'll create an Configuration file
+ # implicitly through the block running on the Initializer, but it's also
+ # possible to create the Configuration instance in advance and pass it in
+ # like this:
+ #
+ # config = Rails::Configuration.new
+ # Rails::Initializer.run(:process, config)
+ class Configuration
+ # The application's base directory.
+ attr_reader :root_path
+
+ # A stub for setting options on ActionController::Base
+ attr_accessor :action_controller
+
+ # A stub for setting options on ActionMailer::Base
+ attr_accessor :action_mailer
+
+ # A stub for setting options on ActionView::Base
+ attr_accessor :action_view
+
+ # A stub for setting options on ActiveRecord::Base
+ attr_accessor :active_record
+
+ # A stub for setting options on ActiveRecord::Base
+ attr_accessor :active_resource
+
+ # Whether or not classes should be cached (set to false if you want
+ # application classes to be reloaded on each request)
+ attr_accessor :cache_classes
+
+ # The list of paths that should be searched for controllers. (Defaults
+ # to <tt>app/controllers</tt> and <tt>components</tt>.)
+ attr_accessor :controller_paths
+
+ # The path to the database configuration file to use. (Defaults to
+ # <tt>config/database.yml</tt>.)
+ attr_accessor :database_configuration_file
+
+ # The list of rails framework components that should be loaded. (Defaults
+ # to <tt>:active_record</tt>, <tt>:action_controller</tt>,
+ # <tt>:action_view</tt>, <tt>:action_mailer</tt>, and
+ # <tt>:active_resource</tt>).
+ attr_accessor :frameworks
+
+ # An array of additional paths to prepend to the load path. By default,
+ # all +app+, +lib+, +vendor+ and mock paths are included in this list.
+ attr_accessor :load_paths
+
+ # An array of paths from which Rails will automatically load from only once.
+ # All elements of this array must also be in +load_paths+.
+ attr_accessor :load_once_paths
+
+ # The log level to use for the default Rails logger. In production mode,
+ # this defaults to <tt>:info</tt>. In development mode, it defaults to
+ # <tt>:debug</tt>.
+ attr_accessor :log_level
+
+ # The path to the log file to use. Defaults to log/#{environment}.log
+ # (e.g. log/development.log or log/production.log).
+ attr_accessor :log_path
+
+ # The specific logger to use. By default, a logger will be created and
+ # initialized using #log_path and #log_level, but a programmer may
+ # specifically set the logger to use via this accessor and it will be
+ # used directly.
+ attr_accessor :logger
+
+ # The root of the application's views. (Defaults to <tt>app/views</tt>.)
+ attr_accessor :view_path
+
+ # Set to +true+ if you want to be warned (noisily) when you try to invoke
+ # any method of +nil+. Set to +false+ for the standard Ruby behavior.
+ attr_accessor :whiny_nils
+
+ # The list of plugins to load. If this is set to <tt>nil</tt>, all plugins will
+ # be loaded. If this is set to <tt>[]</tt>, no plugins will be loaded. Otherwise,
+ # plugins will be loaded in the order specified.
+ attr_reader :plugins
+ def plugins=(plugins)
+ @plugins = plugins.nil? ? nil : plugins.map { |p| p.to_sym }
+ end
+
+ # The path to the root of the plugins directory. By default, it is in
+ # <tt>vendor/plugins</tt>.
+ attr_accessor :plugin_paths
+
+ # The classes that handle finding the desired plugins that you'd like to load for
+ # your application. By default it is the Rails::Plugin::FileSystemLocator which finds
+ # plugins to load in <tt>vendor/plugins</tt>. You can hook into gem location by subclassing
+ # Rails::Plugin::Locator and adding it onto the list of <tt>plugin_locators</tt>.
+ attr_accessor :plugin_locators
+
+ # The class that handles loading each plugin. Defaults to Rails::Plugin::Loader, but
+ # a sub class would have access to fine grained modification of the loading behavior. See
+ # the implementation of Rails::Plugin::Loader for more details.
+ attr_accessor :plugin_loader
+
+ # Deprecated options:
+ def breakpoint_server(_ = nil)
+ $stderr.puts %(
+ *******************************************************************
+ * config.breakpoint_server has been deprecated and has no effect. *
+ *******************************************************************
+ )
+ end
+ alias_method :breakpoint_server=, :breakpoint_server
+
+ # Create a new Configuration instance, initialized with the default
+ # values.
+ def initialize
+ set_root_path!
+
+ self.frameworks = default_frameworks
+ self.load_paths = default_load_paths
+ self.load_once_paths = default_load_once_paths
+ self.log_path = default_log_path
+ self.log_level = default_log_level
+ self.view_path = default_view_path
+ self.controller_paths = default_controller_paths
+ self.cache_classes = default_cache_classes
+ self.whiny_nils = default_whiny_nils
+ self.plugins = default_plugins
+ self.plugin_paths = default_plugin_paths
+ self.plugin_locators = default_plugin_locators
+ self.plugin_loader = default_plugin_loader
+ self.database_configuration_file = default_database_configuration_file
+
+ for framework in default_frameworks
+ self.send("#{framework}=", Rails::OrderedOptions.new)
+ end
+ end
+
+ # Set the root_path to RAILS_ROOT and canonicalize it.
+ def set_root_path!
+ raise 'RAILS_ROOT is not set' unless defined?(::RAILS_ROOT)
+ raise 'RAILS_ROOT is not a directory' unless File.directory?(::RAILS_ROOT)
+
+ @root_path =
+ # Pathname is incompatible with Windows, but Windows doesn't have
+ # real symlinks so File.expand_path is safe.
+ if RUBY_PLATFORM =~ /(:?mswin|mingw)/
+ File.expand_path(::RAILS_ROOT)
+
+ # Otherwise use Pathname#realpath which respects symlinks.
+ else
+ Pathname.new(::RAILS_ROOT).realpath.to_s
+ end
+
+ Object.const_set(:RELATIVE_RAILS_ROOT, ::RAILS_ROOT.dup) unless defined?(::RELATIVE_RAILS_ROOT)
+ ::RAILS_ROOT.replace @root_path
+ end
+
+ # Loads and returns the contents of the #database_configuration_file. The
+ # contents of the file are processed via ERB before being sent through
+ # YAML::load.
+ def database_configuration
+ YAML::load(ERB.new(IO.read(database_configuration_file)).result)
+ end
+
+ # The path to the current environment's file (development.rb, etc.). By
+ # default the file is at <tt>config/environments/#{environment}.rb</tt>.
+ def environment_path
+ "#{root_path}/config/environments/#{environment}.rb"
+ end
+
+ # Return the currently selected environment. By default, it returns the
+ # value of the +RAILS_ENV+ constant.
+ def environment
+ ::RAILS_ENV
+ end
+
+ # Adds a block which will be executed after rails has been fully initialized.
+ # Useful for per-environment configuration which depends on the framework being
+ # fully initialized.
+ def after_initialize(&after_initialize_block)
+ after_initialize_blocks << after_initialize_block if after_initialize_block
+ end
+
+ # Returns the blocks added with Configuration#after_initialize
+ def after_initialize_blocks
+ @after_initialize_blocks ||= []
+ end
+
+ # Add a preparation callback that will run before every request in development
+ # mode, or before the first request in production.
+ #
+ # See Dispatcher#to_prepare.
+ def to_prepare(&callback)
+ require 'dispatcher' unless defined?(::Dispatcher)
+ Dispatcher.to_prepare(&callback)
+ end
+
+ def builtin_directories
+ # Include builtins only in the development environment.
+ (environment == 'development') ? Dir["#{RAILTIES_PATH}/builtin/*/"] : []
+ end
+
+ def framework_paths
+ paths = %w(railties railties/lib activesupport/lib)
+ paths << 'actionpack/lib' if frameworks.include? :action_controller or frameworks.include? :action_view
+
+ [:active_record, :action_mailer, :active_resource, :action_web_service].each do |framework|
+ paths << "#{framework.to_s.gsub('_', '')}/lib" if frameworks.include? framework
+ end
+
+ paths.map { |dir| "#{framework_root_path}/#{dir}" }.select { |dir| File.directory?(dir) }
+ end
+
+ private
+ def framework_root_path
+ defined?(::RAILS_FRAMEWORK_ROOT) ? ::RAILS_FRAMEWORK_ROOT : "#{root_path}/vendor/rails"
+ end
+
+ def default_frameworks
+ [ :active_record, :action_controller, :action_view, :action_mailer, :active_resource ]
+ end
+
+ def default_load_paths
+ paths = ["#{root_path}/test/mocks/#{environment}"]
+
+ # Add the app's controller directory
+ paths.concat(Dir["#{root_path}/app/controllers/"])
+
+ # Then components subdirectories.
+ paths.concat(Dir["#{root_path}/components/[_a-z]*"])
+
+ # Followed by the standard includes.
+ paths.concat %w(
+ app
+ app/models
+ app/controllers
+ app/helpers
+ app/services
+ components
+ config
+ lib
+ vendor
+ ).map { |dir| "#{root_path}/#{dir}" }.select { |dir| File.directory?(dir) }
+
+ paths.concat builtin_directories
+ end
+
+ # Doesn't matter since plugins aren't in load_paths yet.
+ def default_load_once_paths
+ []
+ end
+
+ def default_log_path
+ File.join(root_path, 'log', "#{environment}.log")
+ end
+
+ def default_log_level
+ environment == 'production' ? :info : :debug
+ end
+
+ def default_database_configuration_file
+ File.join(root_path, 'config', 'database.yml')
+ end
+
+ def default_view_path
+ File.join(root_path, 'app', 'views')
+ end
+
+ def default_controller_paths
+ paths = [File.join(root_path, 'app', 'controllers')]
+ paths.concat builtin_directories
+ paths
+ end
+
+ def default_dependency_mechanism
+ :load
+ end
+
+ def default_cache_classes
+ false
+ end
+
+ def default_whiny_nils
+ false
+ end
+
+ def default_plugins
+ nil
+ end
+
+ def default_plugin_paths
+ ["#{root_path}/vendor/plugins"]
+ end
+
+ def default_plugin_locators
+ [Plugin::FileSystemLocator]
+ end
+
+ def default_plugin_loader
+ Plugin::Loader
+ end
+ end
+end
+
+# Needs to be duplicated from Active Support since its needed before Active
+# Support is available. Here both Options and Hash are namespaced to prevent
+# conflicts with other implementations AND with the classes residing in ActiveSupport.
+class Rails::OrderedOptions < Array #:nodoc:
+ def []=(key, value)
+ key = key.to_sym
+
+ if pair = find_pair(key)
+ pair.pop
+ pair << value
+ else
+ self << [key, value]
+ end
+ end
+
+ def [](key)
+ pair = find_pair(key.to_sym)
+ pair ? pair.last : nil
+ end
+
+ def method_missing(name, *args)
+ if name.to_s =~ /(.*)=$/
+ self[$1.to_sym] = args.first
+ else
+ self[name]
+ end
+ end
+
+ private
+ def find_pair(key)
+ self.each { |i| return i if i.first == key }
+ return false
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails/plugin.rb b/vendor/rails-2.0.2/railties/lib/rails/plugin.rb
new file mode 100644
index 000000000..be392195d
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails/plugin.rb
@@ -0,0 +1,84 @@
+module Rails
+
+ # The Plugin class should be an object which provides the following methods:
+ #
+ # * +name+ - used during initialisation to order the plugin (based on name and
+ # the contents of <tt>config.plugins</tt>)
+ # * +valid?+ - returns true if this plugin can be loaded
+ # * +load_paths+ - each path within the returned array will be added to the $LOAD_PATH
+ # * +load+ - finally 'load' the plugin.
+ #
+ # These methods are expected by the Rails::Plugin::Locator and Rails::Plugin::Loader classes.
+ # The default implementation returns the <tt>lib</tt> directory as its </tt>load_paths</tt>,
+ # and evaluates <tt>init.rb</tt> when <tt>load</tt> is called.
+ class Plugin
+ include Comparable
+
+ attr_reader :directory, :name
+
+ def initialize(directory)
+ @directory = directory
+ @name = File.basename(@directory) rescue nil
+ @loaded = false
+ end
+
+ def valid?
+ File.directory?(directory) && (has_lib_directory? || has_init_file?)
+ end
+
+ # Returns a list of paths this plugin wishes to make available in $LOAD_PATH
+ def load_paths
+ report_nonexistant_or_empty_plugin! unless valid?
+ has_lib_directory? ? [lib_path] : []
+ end
+
+ # Evaluates a plugin's init.rb file
+ def load(initializer)
+ return if loaded?
+ report_nonexistant_or_empty_plugin! unless valid?
+ evaluate_init_rb(initializer)
+ @loaded = true
+ end
+
+ def loaded?
+ @loaded
+ end
+
+ def <=>(other_plugin)
+ name <=> other_plugin.name
+ end
+
+ private
+
+ def report_nonexistant_or_empty_plugin!
+ raise LoadError, "Can not find the plugin named: #{name}"
+ end
+
+ def lib_path
+ File.join(directory, 'lib')
+ end
+
+ def init_path
+ File.join(directory, 'init.rb')
+ end
+
+ def has_lib_directory?
+ File.directory?(lib_path)
+ end
+
+ def has_init_file?
+ File.file?(init_path)
+ end
+
+ def evaluate_init_rb(initializer)
+ if has_init_file?
+ silence_warnings do
+ # Allow plugins to reference the current configuration object
+ config = initializer.configuration
+
+ eval(IO.read(init_path), binding, init_path)
+ end
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/railties/lib/rails/plugin/loader.rb b/vendor/rails-2.0.2/railties/lib/rails/plugin/loader.rb
new file mode 100644
index 000000000..438afa4d3
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails/plugin/loader.rb
@@ -0,0 +1,150 @@
+require "rails/plugin"
+
+module Rails
+ class Plugin
+ class Loader
+ attr_reader :initializer
+
+ # Creates a new Plugin::Loader instance, associated with the given
+ # Rails::Initializer. This default implementation automatically locates
+ # all plugins, and adds all plugin load paths, when it is created. The plugins
+ # are then fully loaded (init.rb is evaluated) when load_plugins is called.
+ #
+ # It is the loader's responsibility to ensure that only the plugins specified
+ # in the configuration are actually loaded, and that the order defined
+ # is respected.
+ def initialize(initializer)
+ @initializer = initializer
+ end
+
+ # Returns the plugins to be loaded, in the order they should be loaded.
+ def plugins
+ @plugins ||= all_plugins.select { |plugin| should_load?(plugin) }.sort { |p1, p2| order_plugins(p1, p2) }
+ end
+
+ # Returns all the plugins that could be found by the current locators.
+ def all_plugins
+ @all_plugins ||= locate_plugins
+ @all_plugins
+ end
+
+ def load_plugins
+ plugins.each do |plugin|
+ plugin.load(initializer)
+ register_plugin_as_loaded(plugin)
+ end
+ ensure_all_registered_plugins_are_loaded!
+ end
+
+ # Adds the load paths for every plugin into the $LOAD_PATH. Plugin load paths are
+ # added *after* the application's <tt>lib</tt> directory, to ensure that an application
+ # can always override code within a plugin.
+ #
+ # Plugin load paths are also added to Dependencies.load_paths, and Dependencies.load_once_paths.
+ def add_plugin_load_paths
+ plugins.each do |plugin|
+ plugin.load_paths.each do |path|
+ $LOAD_PATH.insert(application_lib_index + 1, path)
+ Dependencies.load_paths << path
+ Dependencies.load_once_paths << path
+ end
+ end
+ $LOAD_PATH.uniq!
+ end
+
+ protected
+
+ # The locate_plugins method uses each class in config.plugin_locators to
+ # find the set of all plugins available to this Rails application.
+ def locate_plugins
+ configuration.plugin_locators.map { |locator|
+ locator.new(initializer).plugins
+ }.flatten
+ # TODO: sorting based on config.plugins
+ end
+
+ def register_plugin_as_loaded(plugin)
+ initializer.loaded_plugins << plugin
+ end
+
+ def configuration
+ initializer.configuration
+ end
+
+ def should_load?(plugin)
+ # uses Plugin#name and Plugin#valid?
+ enabled?(plugin) && plugin.valid?
+ end
+
+ def order_plugins(plugin_a, plugin_b)
+ if !explicit_plugin_loading_order?
+ plugin_a <=> plugin_b
+ else
+ if !explicitly_enabled?(plugin_a) && !explicitly_enabled?(plugin_b)
+ plugin_a <=> plugin_b
+ else
+ effective_order_of(plugin_a) <=> effective_order_of(plugin_b)
+ end
+ end
+ end
+
+ def effective_order_of(plugin)
+ if explicitly_enabled?(plugin)
+ registered_plugin_names.index(plugin.name)
+ else
+ registered_plugin_names.index('all')
+ end
+ end
+
+ def application_lib_index
+ $LOAD_PATH.index(File.join(RAILS_ROOT, 'lib')) || 0
+ end
+
+ def enabled?(plugin)
+ !explicit_plugin_loading_order? || registered?(plugin)
+ end
+
+ def explicit_plugin_loading_order?
+ !registered_plugin_names.nil?
+ end
+
+ def registered?(plugin)
+ explicit_plugin_loading_order? && registered_plugins_names_plugin?(plugin)
+ end
+
+ def explicitly_enabled?(plugin)
+ !explicit_plugin_loading_order? || explicitly_registered?(plugin)
+ end
+
+ def explicitly_registered?(plugin)
+ explicit_plugin_loading_order? && registered_plugin_names.include?(plugin.name)
+ end
+
+ def registered_plugins_names_plugin?(plugin)
+ registered_plugin_names.include?(plugin.name) || registered_plugin_names.include?('all')
+ end
+
+ # The plugins that have been explicitly listed with config.plugins. If this list is nil
+ # then it means the client does not care which plugins or in what order they are loaded,
+ # so we load all in alphabetical order. If it is an empty array, we load no plugins, if it is
+ # non empty, we load the named plugins in the order specified.
+ def registered_plugin_names
+ configuration.plugins ? configuration.plugins.map(&:to_s) : nil
+ end
+
+ def loaded?(plugin_name)
+ initializer.loaded_plugins.detect { |plugin| plugin.name == plugin_name.to_s }
+ end
+
+ def ensure_all_registered_plugins_are_loaded!
+ if explicit_plugin_loading_order?
+ if configuration.plugins.detect {|plugin| plugin != :all && !loaded?(plugin) }
+ missing_plugins = configuration.plugins - (plugins + [:all])
+ raise LoadError, "Could not locate the following plugins: #{missing_plugins.to_sentence}"
+ end
+ end
+ end
+
+ end
+ end
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/railties/lib/rails/plugin/locator.rb b/vendor/rails-2.0.2/railties/lib/rails/plugin/locator.rb
new file mode 100644
index 000000000..b27e904b1
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails/plugin/locator.rb
@@ -0,0 +1,78 @@
+module Rails
+ class Plugin
+
+ # The Plugin::Locator class should be subclasses to provide custom plugin-finding
+ # abilities to Rails (i.e. loading plugins from Gems, etc). Each subclass should implement
+ # the <tt>located_plugins</tt> method, which return an array of Plugin objects that have been found.
+ class Locator
+ include Enumerable
+
+ attr_reader :initializer
+
+ def initialize(initializer)
+ @initializer = initializer
+ end
+
+ # This method should return all the plugins which this Plugin::Locator can find
+ # These will then be used by the current Plugin::Loader, which is responsible for actually
+ # loading the plugins themselves
+ def plugins
+ raise "The `plugins' method must be defined by concrete subclasses of #{self.class}"
+ end
+
+ def each(&block)
+ plugins.each(&block)
+ end
+
+ def plugin_names
+ plugins.map(&:name)
+ end
+ end
+
+ # The Rails::Plugin::FileSystemLocator will try to locate plugins by examining the directories
+ # the the paths given in configuration.plugin_paths. Any plugins that can be found are returned
+ # in a list.
+ #
+ # The criteria for a valid plugin in this case is found in Rails::Plugin#valid?, although
+ # other subclasses of Rails::Plugin::Locator can of course use different conditions.
+ class FileSystemLocator < Locator
+
+ # Returns all the plugins which can be loaded in the filesystem, under the paths given
+ # by configuration.plugin_paths.
+ def plugins
+ initializer.configuration.plugin_paths.flatten.inject([]) do |plugins, path|
+ plugins.concat locate_plugins_under(path)
+ plugins
+ end.flatten
+ end
+
+ private
+
+ # Attempts to create a plugin from the given path. If the created plugin is valid?
+ # (see Rails::Plugin#valid?) then the plugin instance is returned; otherwise nil.
+ def create_plugin(path)
+ plugin = Rails::Plugin.new(path)
+ plugin.valid? ? plugin : nil
+ end
+
+ # This starts at the base path looking for valid plugins (see Rails::Plugin#valid?).
+ # Since plugins can be nested arbitrarily deep within an unspecified number of intermediary
+ # directories, this method runs recursively until it finds a plugin directory, e.g.
+ #
+ # locate_plugins_under('vendor/plugins/acts/acts_as_chunky_bacon')
+ # => <Rails::Plugin name: 'acts_as_chunky_bacon' ... >
+ #
+ def locate_plugins_under(base_path)
+ Dir.glob(File.join(base_path, '*')).inject([]) do |plugins, path|
+ if plugin = create_plugin(path)
+ plugins << plugin
+ elsif File.directory?(path)
+ plugins.concat locate_plugins_under(path)
+ end
+ plugins
+ end
+ end
+
+ end
+ end
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/railties/lib/rails/version.rb b/vendor/rails-2.0.2/railties/lib/rails/version.rb
new file mode 100644
index 000000000..da9064573
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails/version.rb
@@ -0,0 +1,9 @@
+module Rails
+ module VERSION #:nodoc:
+ MAJOR = 2
+ MINOR = 0
+ TINY = 2
+
+ STRING = [MAJOR, MINOR, TINY].join('.')
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator.rb b/vendor/rails-2.0.2/railties/lib/rails_generator.rb
new file mode 100644
index 000000000..9f0ffc156
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator.rb
@@ -0,0 +1,43 @@
+#--
+# Copyright (c) 2004 Jeremy Kemper
+#
+# 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.
+#++
+
+$:.unshift(File.dirname(__FILE__))
+$:.unshift(File.dirname(__FILE__) + "/../../activesupport/lib")
+
+begin
+ require 'active_support'
+rescue LoadError
+ require 'rubygems'
+ gem 'activesupport'
+end
+
+require 'rails_generator/base'
+require 'rails_generator/lookup'
+require 'rails_generator/commands'
+
+Rails::Generator::Base.send(:include, Rails::Generator::Lookup)
+Rails::Generator::Base.send(:include, Rails::Generator::Commands)
+
+# Set up a default logger for convenience.
+require 'rails_generator/simple_logger'
+Rails::Generator::Base.logger = Rails::Generator::SimpleLogger.new(STDOUT)
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/base.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/base.rb
new file mode 100644
index 000000000..1ebcff906
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/base.rb
@@ -0,0 +1,263 @@
+require File.dirname(__FILE__) + '/options'
+require File.dirname(__FILE__) + '/manifest'
+require File.dirname(__FILE__) + '/spec'
+require File.dirname(__FILE__) + '/generated_attribute'
+
+module Rails
+ # Rails::Generator is a code generation platform tailored for the Rails
+ # web application framework. Generators are easily invoked within Rails
+ # applications to add and remove components such as models and controllers.
+ # New generators are easy to create and may be distributed as RubyGems,
+ # tarballs, or Rails plugins for inclusion system-wide, per-user,
+ # or per-application.
+ #
+ # For actual examples see the rails_generator/generators directory in the
+ # Rails source (or the +railties+ directory if you have frozen the Rails
+ # source in your application).
+ #
+ # Generators may subclass other generators to provide variations that
+ # require little or no new logic but replace the template files.
+ #
+ # For a RubyGem, put your generator class and templates in the +lib+
+ # directory. For a Rails plugin, make a +generators+ directory at the
+ # root of your plugin.
+ #
+ # The layout of generator files can be seen in the built-in
+ # +controller+ generator:
+ #
+ # generators/
+ # components/
+ # controller/
+ # controller_generator.rb
+ # templates/
+ # controller.rb
+ # functional_test.rb
+ # helper.rb
+ # view.html.erb
+ #
+ # The directory name (+controller+) matches the name of the generator file
+ # (controller_generator.rb) and class (+ControllerGenerator+). The files
+ # that will be copied or used as templates are stored in the +templates+
+ # directory.
+ #
+ # The filenames of the templates don't matter, but choose something that
+ # will be self-explanatory since you will be referencing these in the
+ # +manifest+ method inside your generator subclass.
+ #
+ #
+ module Generator
+ class GeneratorError < StandardError; end
+ class UsageError < GeneratorError; end
+
+
+ # The base code generator is bare-bones. It sets up the source and
+ # destination paths and tells the logger whether to keep its trap shut.
+ #
+ # It's useful for copying files such as stylesheets, images, or
+ # javascripts.
+ #
+ # For more comprehensive template-based passive code generation with
+ # arguments, you'll want Rails::Generator::NamedBase.
+ #
+ # Generators create a manifest of the actions they perform then hand
+ # the manifest to a command which replays the actions to do the heavy
+ # lifting (such as checking for existing files or creating directories
+ # if needed). Create, destroy, and list commands are included. Since a
+ # single manifest may be used by any command, creating new generators is
+ # as simple as writing some code templates and declaring what you'd like
+ # to do with them.
+ #
+ # The manifest method must be implemented by subclasses, returning a
+ # Rails::Generator::Manifest. The +record+ method is provided as a
+ # convenience for manifest creation. Example:
+ #
+ # class StylesheetGenerator < Rails::Generator::Base
+ # def manifest
+ # record do |m|
+ # m.directory('public/stylesheets')
+ # m.file('application.css', 'public/stylesheets/application.css')
+ # end
+ # end
+ # end
+ #
+ # See Rails::Generator::Commands::Create for a list of methods available
+ # to the manifest.
+ class Base
+ include Options
+
+ # Declare default options for the generator. These options
+ # are inherited to subclasses.
+ default_options :collision => :ask, :quiet => false
+
+ # A logger instance available everywhere in the generator.
+ cattr_accessor :logger
+
+ # Every generator that is dynamically looked up is tagged with a
+ # Spec describing where it was found.
+ class_inheritable_accessor :spec
+
+ attr_reader :source_root, :destination_root, :args
+
+ def initialize(runtime_args, runtime_options = {})
+ @args = runtime_args
+ parse!(@args, runtime_options)
+
+ # Derive source and destination paths.
+ @source_root = options[:source] || File.join(spec.path, 'templates')
+ if options[:destination]
+ @destination_root = options[:destination]
+ elsif defined? ::RAILS_ROOT
+ @destination_root = ::RAILS_ROOT
+ end
+
+ # Silence the logger if requested.
+ logger.quiet = options[:quiet]
+
+ # Raise usage error if help is requested.
+ usage if options[:help]
+ end
+
+ # Generators must provide a manifest. Use the +record+ method to create
+ # a new manifest and record your generator's actions.
+ def manifest
+ raise NotImplementedError, "No manifest for '#{spec.name}' generator."
+ end
+
+ # Return the full path from the source root for the given path.
+ # Example for source_root = '/source':
+ # source_path('some/path.rb') == '/source/some/path.rb'
+ #
+ # The given path may include a colon ':' character to indicate that
+ # the file belongs to another generator. This notation allows any
+ # generator to borrow files from another. Example:
+ # source_path('model:fixture.yml') = '/model/source/path/fixture.yml'
+ def source_path(relative_source)
+ # Check whether we're referring to another generator's file.
+ name, path = relative_source.split(':', 2)
+
+ # If not, return the full path to our source file.
+ if path.nil?
+ File.join(source_root, name)
+
+ # Otherwise, ask our referral for the file.
+ else
+ # FIXME: this is broken, though almost always true. Others'
+ # source_root are not necessarily the templates dir.
+ File.join(self.class.lookup(name).path, 'templates', path)
+ end
+ end
+
+ # Return the full path from the destination root for the given path.
+ # Example for destination_root = '/dest':
+ # destination_path('some/path.rb') == '/dest/some/path.rb'
+ def destination_path(relative_destination)
+ File.join(destination_root, relative_destination)
+ end
+
+ protected
+ # Convenience method for generator subclasses to record a manifest.
+ def record
+ Rails::Generator::Manifest.new(self) { |m| yield m }
+ end
+
+ # Override with your own usage banner.
+ def banner
+ "Usage: #{$0} #{spec.name} [options]"
+ end
+
+ # Read USAGE from file in generator base path.
+ def usage_message
+ File.read(File.join(spec.path, 'USAGE')) rescue ''
+ end
+ end
+
+
+ # The base generator for named components: models, controllers, mailers,
+ # etc. The target name is taken as the first argument and inflected to
+ # singular, plural, class, file, and table forms for your convenience.
+ # The remaining arguments are aliased to +actions+ as an array for
+ # controller and mailer convenience.
+ #
+ # Several useful local variables and methods are populated in the
+ # +initialize+ method. See below for a list of Attributes and
+ # External Aliases available to both the manifest and to all templates.
+ #
+ # If no name is provided, the generator raises a usage error with content
+ # optionally read from the USAGE file in the generator's base path.
+ #
+ # For example, the +controller+ generator takes the first argument as
+ # the name of the class and subsequent arguments as the names of
+ # actions to be generated:
+ #
+ # ./script/generate controller Article index new create
+ #
+ # See Rails::Generator::Base for a discussion of manifests,
+ # Rails::Generator::Commands::Create for methods available to the manifest,
+ # and Rails::Generator for a general discussion of generators.
+ class NamedBase < Base
+ attr_reader :name, :class_name, :singular_name, :plural_name, :table_name
+ attr_reader :class_path, :file_path, :class_nesting, :class_nesting_depth
+ alias_method :file_name, :singular_name
+ alias_method :actions, :args
+
+ def initialize(runtime_args, runtime_options = {})
+ super
+
+ # Name argument is required.
+ usage if runtime_args.empty?
+
+ @args = runtime_args.dup
+ base_name = @args.shift
+ assign_names!(base_name)
+ end
+
+ protected
+ # Override with your own usage banner.
+ def banner
+ "Usage: #{$0} #{spec.name} #{spec.name.camelize}Name [options]"
+ end
+
+ def attributes
+ @attributes ||= @args.collect do |attribute|
+ Rails::Generator::GeneratedAttribute.new(*attribute.split(":"))
+ end
+ end
+
+
+ private
+ def assign_names!(name)
+ @name = name
+ base_name, @class_path, @file_path, @class_nesting, @class_nesting_depth = extract_modules(@name)
+ @class_name_without_nesting, @singular_name, @plural_name = inflect_names(base_name)
+ @table_name = (!defined?(ActiveRecord::Base) || ActiveRecord::Base.pluralize_table_names) ? plural_name : singular_name
+ @table_name.gsub! '/', '_'
+ if @class_nesting.empty?
+ @class_name = @class_name_without_nesting
+ else
+ @table_name = @class_nesting.underscore << "_" << @table_name
+ @class_name = "#{@class_nesting}::#{@class_name_without_nesting}"
+ end
+ end
+
+ # Extract modules from filesystem-style or ruby-style path:
+ # good/fun/stuff
+ # Good::Fun::Stuff
+ # produce the same results.
+ def extract_modules(name)
+ modules = name.include?('/') ? name.split('/') : name.split('::')
+ name = modules.pop
+ path = modules.map { |m| m.underscore }
+ file_path = (path + [name.underscore]).join('/')
+ nesting = modules.map { |m| m.camelize }.join('::')
+ [name, path, file_path, nesting, modules.size]
+ end
+
+ def inflect_names(name)
+ camel = name.camelize
+ under = camel.underscore
+ plural = under.pluralize
+ [camel, under, plural]
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/commands.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/commands.rb
new file mode 100644
index 000000000..6f90a44b8
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/commands.rb
@@ -0,0 +1,591 @@
+require 'delegate'
+require 'optparse'
+require 'fileutils'
+require 'tempfile'
+require 'erb'
+
+module Rails
+ module Generator
+ module Commands
+ # Here's a convenient way to get a handle on generator commands.
+ # Command.instance('destroy', my_generator) instantiates a Destroy
+ # delegate of my_generator ready to do your dirty work.
+ def self.instance(command, generator)
+ const_get(command.to_s.camelize).new(generator)
+ end
+
+ # Even more convenient access to commands. Include Commands in
+ # the generator Base class to get a nice #command instance method
+ # which returns a delegate for the requested command.
+ def self.included(base)
+ base.send(:define_method, :command) do |command|
+ Commands.instance(command, self)
+ end
+ end
+
+
+ # Generator commands delegate Rails::Generator::Base and implement
+ # a standard set of actions. Their behavior is defined by the way
+ # they respond to these actions: Create brings life; Destroy brings
+ # death; List passively observes.
+ #
+ # Commands are invoked by replaying (or rewinding) the generator's
+ # manifest of actions. See Rails::Generator::Manifest and
+ # Rails::Generator::Base#manifest method that generator subclasses
+ # are required to override.
+ #
+ # Commands allows generators to "plug in" invocation behavior, which
+ # corresponds to the GoF Strategy pattern.
+ class Base < DelegateClass(Rails::Generator::Base)
+ # Replay action manifest. RewindBase subclass rewinds manifest.
+ def invoke!
+ manifest.replay(self)
+ end
+
+ def dependency(generator_name, args, runtime_options = {})
+ logger.dependency(generator_name) do
+ self.class.new(instance(generator_name, args, full_options(runtime_options))).invoke!
+ end
+ end
+
+ # Does nothing for all commands except Create.
+ def class_collisions(*class_names)
+ end
+
+ # Does nothing for all commands except Create.
+ def readme(*args)
+ end
+
+ protected
+ def migration_directory(relative_path)
+ directory(@migration_directory = relative_path)
+ end
+
+ def existing_migrations(file_name)
+ Dir.glob("#{@migration_directory}/[0-9]*_*.rb").grep(/[0-9]+_#{file_name}.rb$/)
+ end
+
+ def migration_exists?(file_name)
+ not existing_migrations(file_name).empty?
+ end
+
+ def current_migration_number
+ Dir.glob("#{RAILS_ROOT}/#{@migration_directory}/[0-9]*_*.rb").inject(0) do |max, file_path|
+ n = File.basename(file_path).split('_', 2).first.to_i
+ if n > max then n else max end
+ end
+ end
+
+ def next_migration_number
+ current_migration_number + 1
+ end
+
+ def next_migration_string(padding = 3)
+ "%.#{padding}d" % next_migration_number
+ end
+
+ def gsub_file(relative_destination, regexp, *args, &block)
+ path = destination_path(relative_destination)
+ content = File.read(path).gsub(regexp, *args, &block)
+ File.open(path, 'wb') { |file| file.write(content) }
+ end
+
+ private
+ # Ask the user interactively whether to force collision.
+ def force_file_collision?(destination, src, dst, file_options = {}, &block)
+ $stdout.print "overwrite #{destination}? (enter \"h\" for help) [Ynaqdh] "
+ case $stdin.gets.chomp
+ when /\Ad\z/i
+ Tempfile.open(File.basename(destination), File.dirname(dst)) do |temp|
+ temp.write render_file(src, file_options, &block)
+ temp.rewind
+ $stdout.puts `#{diff_cmd} #{dst} #{temp.path}`
+ end
+ puts "retrying"
+ raise 'retry diff'
+ when /\Aa\z/i
+ $stdout.puts "forcing #{spec.name}"
+ options[:collision] = :force
+ when /\Aq\z/i
+ $stdout.puts "aborting #{spec.name}"
+ raise SystemExit
+ when /\An\z/i then :skip
+ when /\Ay\z/i then :force
+ else
+ $stdout.puts <<-HELP
+Y - yes, overwrite
+n - no, do not overwrite
+a - all, overwrite this and all others
+q - quit, abort
+d - diff, show the differences between the old and the new
+h - help, show this help
+HELP
+ raise 'retry'
+ end
+ rescue
+ retry
+ end
+
+ def diff_cmd
+ ENV['RAILS_DIFF'] || 'diff -u'
+ end
+
+ def render_template_part(template_options)
+ # Getting Sandbox to evaluate part template in it
+ part_binding = template_options[:sandbox].call.sandbox_binding
+ part_rel_path = template_options[:insert]
+ part_path = source_path(part_rel_path)
+
+ # Render inner template within Sandbox binding
+ rendered_part = ERB.new(File.readlines(part_path).join, nil, '-').result(part_binding)
+ begin_mark = template_part_mark(template_options[:begin_mark], template_options[:mark_id])
+ end_mark = template_part_mark(template_options[:end_mark], template_options[:mark_id])
+ begin_mark + rendered_part + end_mark
+ end
+
+ def template_part_mark(name, id)
+ "<!--[#{name}:#{id}]-->\n"
+ end
+ end
+
+ # Base class for commands which handle generator actions in reverse, such as Destroy.
+ class RewindBase < Base
+ # Rewind action manifest.
+ def invoke!
+ manifest.rewind(self)
+ end
+ end
+
+
+ # Create is the premier generator command. It copies files, creates
+ # directories, renders templates, and more.
+ class Create < Base
+
+ # Check whether the given class names are already taken by
+ # Ruby or Rails. In the future, expand to check other namespaces
+ # such as the rest of the user's app.
+ def class_collisions(*class_names)
+ class_names.flatten.each do |class_name|
+ # Convert to string to allow symbol arguments.
+ class_name = class_name.to_s
+
+ # Skip empty strings.
+ next if class_name.strip.empty?
+
+ # Split the class from its module nesting.
+ nesting = class_name.split('::')
+ name = nesting.pop
+
+ # Extract the last Module in the nesting.
+ last = nesting.inject(Object) { |last, nest|
+ break unless last.const_defined?(nest)
+ last.const_get(nest)
+ }
+
+ # If the last Module exists, check whether the given
+ # class exists and raise a collision if so.
+ if last and last.const_defined?(name.camelize)
+ raise_class_collision(class_name)
+ end
+ end
+ end
+
+ # Copy a file from source to destination with collision checking.
+ #
+ # The file_options hash accepts :chmod and :shebang and :collision options.
+ # :chmod sets the permissions of the destination file:
+ # file 'config/empty.log', 'log/test.log', :chmod => 0664
+ # :shebang sets the #!/usr/bin/ruby line for scripts
+ # file 'bin/generate.rb', 'script/generate', :chmod => 0755, :shebang => '/usr/bin/env ruby'
+ # :collision sets the collision option only for the destination file:
+ # file 'settings/server.yml', 'config/server.yml', :collision => :skip
+ #
+ # Collisions are handled by checking whether the destination file
+ # exists and either skipping the file, forcing overwrite, or asking
+ # the user what to do.
+ def file(relative_source, relative_destination, file_options = {}, &block)
+ # Determine full paths for source and destination files.
+ source = source_path(relative_source)
+ destination = destination_path(relative_destination)
+ destination_exists = File.exist?(destination)
+
+ # If source and destination are identical then we're done.
+ if destination_exists and identical?(source, destination, &block)
+ return logger.identical(relative_destination)
+ end
+
+ # Check for and resolve file collisions.
+ if destination_exists
+
+ # Make a choice whether to overwrite the file. :force and
+ # :skip already have their mind made up, but give :ask a shot.
+ choice = case (file_options[:collision] || options[:collision]).to_sym #|| :ask
+ when :ask then force_file_collision?(relative_destination, source, destination, file_options, &block)
+ when :force then :force
+ when :skip then :skip
+ else raise "Invalid collision option: #{options[:collision].inspect}"
+ end
+
+ # Take action based on our choice. Bail out if we chose to
+ # skip the file; otherwise, log our transgression and continue.
+ case choice
+ when :force then logger.force(relative_destination)
+ when :skip then return(logger.skip(relative_destination))
+ else raise "Invalid collision choice: #{choice}.inspect"
+ end
+
+ # File doesn't exist so log its unbesmirched creation.
+ else
+ logger.create relative_destination
+ end
+
+ # If we're pretending, back off now.
+ return if options[:pretend]
+
+ # Write destination file with optional shebang. Yield for content
+ # if block given so templaters may render the source file. If a
+ # shebang is requested, replace the existing shebang or insert a
+ # new one.
+ File.open(destination, 'wb') do |dest|
+ dest.write render_file(source, file_options, &block)
+ end
+
+ # Optionally change permissions.
+ if file_options[:chmod]
+ FileUtils.chmod(file_options[:chmod], destination)
+ end
+
+ # Optionally add file to subversion
+ system("svn add #{destination}") if options[:svn]
+ end
+
+ # Checks if the source and the destination file are identical. If
+ # passed a block then the source file is a template that needs to first
+ # be evaluated before being compared to the destination.
+ def identical?(source, destination, &block)
+ return false if File.directory? destination
+ source = block_given? ? File.open(source) {|sf| yield(sf)} : IO.read(source)
+ destination = IO.read(destination)
+ source == destination
+ end
+
+ # Generate a file for a Rails application using an ERuby template.
+ # Looks up and evaluates a template by name and writes the result.
+ #
+ # The ERB template uses explicit trim mode to best control the
+ # proliferation of whitespace in generated code. <%- trims leading
+ # whitespace; -%> trims trailing whitespace including one newline.
+ #
+ # A hash of template options may be passed as the last argument.
+ # The options accepted by the file are accepted as well as :assigns,
+ # a hash of variable bindings. Example:
+ # template 'foo', 'bar', :assigns => { :action => 'view' }
+ #
+ # Template is implemented in terms of file. It calls file with a
+ # block which takes a file handle and returns its rendered contents.
+ def template(relative_source, relative_destination, template_options = {})
+ file(relative_source, relative_destination, template_options) do |file|
+ # Evaluate any assignments in a temporary, throwaway binding.
+ vars = template_options[:assigns] || {}
+ b = binding
+ vars.each { |k,v| eval "#{k} = vars[:#{k}] || vars['#{k}']", b }
+
+ # Render the source file with the temporary binding.
+ ERB.new(file.read, nil, '-').result(b)
+ end
+ end
+
+ def complex_template(relative_source, relative_destination, template_options = {})
+ options = template_options.dup
+ options[:assigns] ||= {}
+ options[:assigns]['template_for_inclusion'] = render_template_part(template_options)
+ template(relative_source, relative_destination, options)
+ end
+
+ # Create a directory including any missing parent directories.
+ # Always directories which exist.
+ def directory(relative_path)
+ path = destination_path(relative_path)
+ if File.exist?(path)
+ logger.exists relative_path
+ else
+ logger.create relative_path
+ unless options[:pretend]
+ FileUtils.mkdir_p(path)
+
+ # Subversion doesn't do path adds, so we need to add
+ # each directory individually.
+ # So stack up the directory tree and add the paths to
+ # subversion in order without recursion.
+ if options[:svn]
+ stack=[relative_path]
+ until File.dirname(stack.last) == stack.last # dirname('.') == '.'
+ stack.push File.dirname(stack.last)
+ end
+ stack.reverse_each do |rel_path|
+ svn_path = destination_path(rel_path)
+ system("svn add -N #{svn_path}") unless File.directory?(File.join(svn_path, '.svn'))
+ end
+ end
+ end
+ end
+ end
+
+ # Display a README.
+ def readme(*relative_sources)
+ relative_sources.flatten.each do |relative_source|
+ logger.readme relative_source
+ puts File.read(source_path(relative_source)) unless options[:pretend]
+ end
+ end
+
+ # When creating a migration, it knows to find the first available file in db/migrate and use the migration.rb template.
+ def migration_template(relative_source, relative_destination, template_options = {})
+ migration_directory relative_destination
+ migration_file_name = template_options[:migration_file_name] || file_name
+ raise "Another migration is already named #{migration_file_name}: #{existing_migrations(migration_file_name).first}" if migration_exists?(migration_file_name)
+ template(relative_source, "#{relative_destination}/#{next_migration_string}_#{migration_file_name}.rb", template_options)
+ end
+
+ def route_resources(*resources)
+ resource_list = resources.map { |r| r.to_sym.inspect }.join(', ')
+ sentinel = 'ActionController::Routing::Routes.draw do |map|'
+
+ logger.route "map.resources #{resource_list}"
+ unless options[:pretend]
+ gsub_file 'config/routes.rb', /(#{Regexp.escape(sentinel)})/mi do |match|
+ "#{match}\n map.resources #{resource_list}\n"
+ end
+ end
+ end
+
+ private
+ def render_file(path, options = {})
+ File.open(path, 'rb') do |file|
+ if block_given?
+ yield file
+ else
+ content = ''
+ if shebang = options[:shebang]
+ content << "#!#{shebang}\n"
+ if line = file.gets
+ content << "line\n" if line !~ /^#!/
+ end
+ end
+ content << file.read
+ end
+ end
+ end
+
+ # Raise a usage error with an informative WordNet suggestion.
+ # Thanks to Florian Gross (flgr).
+ def raise_class_collision(class_name)
+ message = <<end_message
+ The name '#{class_name}' is reserved by Ruby on Rails.
+ Please choose an alternative and run this generator again.
+end_message
+ if suggest = find_synonyms(class_name)
+ message << "\n Suggestions: \n\n"
+ message << suggest.join("\n")
+ end
+ raise UsageError, message
+ end
+
+ SYNONYM_LOOKUP_URI = "http://wordnet.princeton.edu/cgi-bin/webwn2.0?stage=2&word=%s&posnumber=1&searchtypenumber=2&senses=&showglosses=1"
+
+ # Look up synonyms on WordNet. Thanks to Florian Gross (flgr).
+ def find_synonyms(word)
+ require 'open-uri'
+ require 'timeout'
+ timeout(5) do
+ open(SYNONYM_LOOKUP_URI % word) do |stream|
+ data = stream.read.gsub("&nbsp;", " ").gsub("<BR>", "")
+ data.scan(/^Sense \d+\n.+?\n\n/m)
+ end
+ end
+ rescue Exception
+ return nil
+ end
+ end
+
+
+ # Undo the actions performed by a generator. Rewind the action
+ # manifest and attempt to completely erase the results of each action.
+ class Destroy < RewindBase
+ # Remove a file if it exists and is a file.
+ def file(relative_source, relative_destination, file_options = {})
+ destination = destination_path(relative_destination)
+ if File.exist?(destination)
+ logger.rm relative_destination
+ unless options[:pretend]
+ if options[:svn]
+ # If the file has been marked to be added
+ # but has not yet been checked in, revert and delete
+ if options[:svn][relative_destination]
+ system("svn revert #{destination}")
+ FileUtils.rm(destination)
+ else
+ # If the directory is not in the status list, it
+ # has no modifications so we can simply remove it
+ system("svn rm #{destination}")
+ end
+ else
+ FileUtils.rm(destination)
+ end
+ end
+ else
+ logger.missing relative_destination
+ return
+ end
+ end
+
+ # Templates are deleted just like files and the actions take the
+ # same parameters, so simply alias the file method.
+ alias_method :template, :file
+
+ # Remove each directory in the given path from right to left.
+ # Remove each subdirectory if it exists and is a directory.
+ def directory(relative_path)
+ parts = relative_path.split('/')
+ until parts.empty?
+ partial = File.join(parts)
+ path = destination_path(partial)
+ if File.exist?(path)
+ if Dir[File.join(path, '*')].empty?
+ logger.rmdir partial
+ unless options[:pretend]
+ if options[:svn]
+ # If the directory has been marked to be added
+ # but has not yet been checked in, revert and delete
+ if options[:svn][relative_path]
+ system("svn revert #{path}")
+ FileUtils.rmdir(path)
+ else
+ # If the directory is not in the status list, it
+ # has no modifications so we can simply remove it
+ system("svn rm #{path}")
+ end
+ else
+ FileUtils.rmdir(path)
+ end
+ end
+ else
+ logger.notempty partial
+ end
+ else
+ logger.missing partial
+ end
+ parts.pop
+ end
+ end
+
+ def complex_template(*args)
+ # nothing should be done here
+ end
+
+ # When deleting a migration, it knows to delete every file named "[0-9]*_#{file_name}".
+ def migration_template(relative_source, relative_destination, template_options = {})
+ migration_directory relative_destination
+
+ migration_file_name = template_options[:migration_file_name] || file_name
+ unless migration_exists?(migration_file_name)
+ puts "There is no migration named #{migration_file_name}"
+ return
+ end
+
+
+ existing_migrations(migration_file_name).each do |file_path|
+ file(relative_source, file_path, template_options)
+ end
+ end
+
+ def route_resources(*resources)
+ resource_list = resources.map { |r| r.to_sym.inspect }.join(', ')
+ look_for = "\n map.resources #{resource_list}\n"
+ logger.route "map.resources #{resource_list}"
+ gsub_file 'config/routes.rb', /(#{look_for})/mi, ''
+ end
+ end
+
+
+ # List a generator's action manifest.
+ class List < Base
+ def dependency(generator_name, args, options = {})
+ logger.dependency "#{generator_name}(#{args.join(', ')}, #{options.inspect})"
+ end
+
+ def class_collisions(*class_names)
+ logger.class_collisions class_names.join(', ')
+ end
+
+ def file(relative_source, relative_destination, options = {})
+ logger.file relative_destination
+ end
+
+ def template(relative_source, relative_destination, options = {})
+ logger.template relative_destination
+ end
+
+ def complex_template(relative_source, relative_destination, options = {})
+ logger.template "#{options[:insert]} inside #{relative_destination}"
+ end
+
+ def directory(relative_path)
+ logger.directory "#{destination_path(relative_path)}/"
+ end
+
+ def readme(*args)
+ logger.readme args.join(', ')
+ end
+
+ def migration_template(relative_source, relative_destination, options = {})
+ migration_directory relative_destination
+ logger.migration_template file_name
+ end
+
+ def route_resources(*resources)
+ resource_list = resources.map { |r| r.to_sym.inspect }.join(', ')
+ logger.route "map.resources #{resource_list}"
+ end
+ end
+
+ # Update generator's action manifest.
+ class Update < Create
+ def file(relative_source, relative_destination, options = {})
+ # logger.file relative_destination
+ end
+
+ def template(relative_source, relative_destination, options = {})
+ # logger.template relative_destination
+ end
+
+ def complex_template(relative_source, relative_destination, template_options = {})
+
+ begin
+ dest_file = destination_path(relative_destination)
+ source_to_update = File.readlines(dest_file).join
+ rescue Errno::ENOENT
+ logger.missing relative_destination
+ return
+ end
+
+ logger.refreshing "#{template_options[:insert].gsub(/\.erb/,'')} inside #{relative_destination}"
+
+ begin_mark = Regexp.quote(template_part_mark(template_options[:begin_mark], template_options[:mark_id]))
+ end_mark = Regexp.quote(template_part_mark(template_options[:end_mark], template_options[:mark_id]))
+
+ # Refreshing inner part of the template with freshly rendered part.
+ rendered_part = render_template_part(template_options)
+ source_to_update.gsub!(/#{begin_mark}.*?#{end_mark}/m, rendered_part)
+
+ File.open(dest_file, 'w') { |file| file.write(source_to_update) }
+ end
+
+ def directory(relative_path)
+ # logger.directory "#{destination_path(relative_path)}/"
+ end
+ end
+
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generated_attribute.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generated_attribute.rb
new file mode 100644
index 000000000..25af3931d
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generated_attribute.rb
@@ -0,0 +1,42 @@
+require 'optparse'
+
+module Rails
+ module Generator
+ class GeneratedAttribute
+ attr_accessor :name, :type, :column
+
+ def initialize(name, type)
+ @name, @type = name, type.to_sym
+ @column = ActiveRecord::ConnectionAdapters::Column.new(name, nil, @type)
+ end
+
+ def field_type
+ @field_type ||= case type
+ when :integer, :float, :decimal then :text_field
+ when :datetime, :timestamp, :time then :datetime_select
+ when :date then :date_select
+ when :string then :text_field
+ when :text then :text_area
+ when :boolean then :check_box
+ else
+ :text_field
+ end
+ end
+
+ def default
+ @default ||= case type
+ when :integer then 1
+ when :float then 1.5
+ when :decimal then "9.99"
+ when :datetime, :timestamp, :time then Time.now.to_s(:db)
+ when :date then Date.today.to_s(:db)
+ when :string then "MyString"
+ when :text then "MyText"
+ when :boolean then false
+ else
+ ""
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/applications/app/USAGE b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/applications/app/USAGE
new file mode 100644
index 000000000..36d6061a5
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/applications/app/USAGE
@@ -0,0 +1,9 @@
+Description:
+ The 'rails' command creates a new Rails application with a default
+ directory structure and configuration at the path you specify.
+
+Example:
+ rails ~/Code/Ruby/weblog
+
+ This generates a skeletal Rails installation in ~/Code/Ruby/weblog.
+ See the README in the newly created application to get going.
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/applications/app/app_generator.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/applications/app/app_generator.rb
new file mode 100644
index 000000000..1dd72f349
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/applications/app/app_generator.rb
@@ -0,0 +1,179 @@
+require 'rbconfig'
+require 'digest/md5'
+require 'rails_generator/secret_key_generator'
+
+class AppGenerator < Rails::Generator::Base
+ DEFAULT_SHEBANG = File.join(Config::CONFIG['bindir'],
+ Config::CONFIG['ruby_install_name'])
+
+ DATABASES = %w(mysql oracle postgresql sqlite2 sqlite3 frontbase)
+
+ default_options :db => (ENV["RAILS_DEFAULT_DATABASE"] || "sqlite3"),
+ :shebang => DEFAULT_SHEBANG, :freeze => false
+ mandatory_options :source => "#{File.dirname(__FILE__)}/../../../../.."
+
+ def initialize(runtime_args, runtime_options = {})
+ super
+ usage if args.empty?
+ usage("Databases supported for preconfiguration are: #{DATABASES.join(", ")}") if (options[:db] && !DATABASES.include?(options[:db]))
+ @destination_root = args.shift
+ @app_name = File.basename(File.expand_path(@destination_root))
+ end
+
+ def manifest
+ # Use /usr/bin/env if no special shebang was specified
+ script_options = { :chmod => 0755, :shebang => options[:shebang] == DEFAULT_SHEBANG ? nil : options[:shebang] }
+ dispatcher_options = { :chmod => 0755, :shebang => options[:shebang] }
+
+ # duplicate CGI::Session#generate_unique_id
+ md5 = Digest::MD5.new
+ now = Time.now
+ md5 << now.to_s
+ md5 << String(now.usec)
+ md5 << String(rand(0))
+ md5 << String($$)
+ md5 << @app_name
+
+ # Do our best to generate a secure secret key for CookieStore
+ secret = Rails::SecretKeyGenerator.new(@app_name).generate_secret
+
+ record do |m|
+ # Root directory and all subdirectories.
+ m.directory ''
+ BASEDIRS.each { |path| m.directory path }
+
+ # Root
+ m.file "fresh_rakefile", "Rakefile"
+ m.file "README", "README"
+
+ # Application
+ m.template "helpers/application.rb", "app/controllers/application.rb", :assigns => { :app_name => @app_name, :app_secret => md5.hexdigest }
+ m.template "helpers/application_helper.rb", "app/helpers/application_helper.rb"
+ m.template "helpers/test_helper.rb", "test/test_helper.rb"
+
+ # database.yml and .htaccess
+ m.template "configs/databases/#{options[:db]}.yml", "config/database.yml", :assigns => {
+ :app_name => @app_name,
+ :socket => options[:db] == "mysql" ? mysql_socket_location : nil
+ }
+ m.template "configs/routes.rb", "config/routes.rb"
+ m.template "configs/apache.conf", "public/.htaccess"
+
+ # Initializers
+ m.template "configs/initializers/inflections.rb", "config/initializers/inflections.rb"
+ m.template "configs/initializers/mime_types.rb", "config/initializers/mime_types.rb"
+
+ # Environments
+ m.file "environments/boot.rb", "config/boot.rb"
+ m.template "environments/environment.rb", "config/environment.rb", :assigns => { :freeze => options[:freeze], :app_name => @app_name, :app_secret => secret }
+ m.file "environments/production.rb", "config/environments/production.rb"
+ m.file "environments/development.rb", "config/environments/development.rb"
+ m.file "environments/test.rb", "config/environments/test.rb"
+
+ # Scripts
+ %w( about console destroy generate performance/benchmarker performance/profiler performance/request process/reaper process/spawner process/inspector runner server plugin ).each do |file|
+ m.file "bin/#{file}", "script/#{file}", script_options
+ end
+
+ # Dispatches
+ m.file "dispatches/dispatch.rb", "public/dispatch.rb", dispatcher_options
+ m.file "dispatches/dispatch.rb", "public/dispatch.cgi", dispatcher_options
+ m.file "dispatches/dispatch.fcgi", "public/dispatch.fcgi", dispatcher_options
+
+ # HTML files
+ %w(404 422 500 index).each do |file|
+ m.template "html/#{file}.html", "public/#{file}.html"
+ end
+
+ m.template "html/favicon.ico", "public/favicon.ico"
+ m.template "html/robots.txt", "public/robots.txt"
+ m.file "html/images/rails.png", "public/images/rails.png"
+
+ # Javascripts
+ m.file "html/javascripts/prototype.js", "public/javascripts/prototype.js"
+ m.file "html/javascripts/effects.js", "public/javascripts/effects.js"
+ m.file "html/javascripts/dragdrop.js", "public/javascripts/dragdrop.js"
+ m.file "html/javascripts/controls.js", "public/javascripts/controls.js"
+ m.file "html/javascripts/application.js", "public/javascripts/application.js"
+
+ # Docs
+ m.file "doc/README_FOR_APP", "doc/README_FOR_APP"
+
+ # Logs
+ %w(server production development test).each { |file|
+ m.file "configs/empty.log", "log/#{file}.log", :chmod => 0666
+ }
+ end
+ end
+
+ protected
+ def banner
+ "Usage: #{$0} /path/to/your/app [options]"
+ end
+
+ def add_options!(opt)
+ opt.separator ''
+ opt.separator 'Options:'
+ opt.on("-r", "--ruby=path", String,
+ "Path to the Ruby binary of your choice (otherwise scripts use env, dispatchers current path).",
+ "Default: #{DEFAULT_SHEBANG}") { |v| options[:shebang] = v }
+
+ opt.on("-d", "--database=name", String,
+ "Preconfigure for selected database (options: mysql/oracle/postgresql/sqlite2/sqlite3).",
+ "Default: mysql") { |v| options[:db] = v }
+
+ opt.on("-f", "--freeze",
+ "Freeze Rails in vendor/rails from the gems generating the skeleton",
+ "Default: false") { |v| options[:freeze] = v }
+ end
+
+ def mysql_socket_location
+ MYSQL_SOCKET_LOCATIONS.find { |f| File.exist?(f) } unless RUBY_PLATFORM =~ /(:?mswin|mingw)/
+ end
+
+
+ # Installation skeleton. Intermediate directories are automatically
+ # created so don't sweat their absence here.
+ BASEDIRS = %w(
+ app/controllers
+ app/helpers
+ app/models
+ app/views/layouts
+ config/environments
+ config/initializers
+ db
+ doc
+ lib
+ lib/tasks
+ log
+ public/images
+ public/javascripts
+ public/stylesheets
+ script/performance
+ script/process
+ test/fixtures
+ test/functional
+ test/integration
+ test/mocks/development
+ test/mocks/test
+ test/unit
+ vendor
+ vendor/plugins
+ tmp/sessions
+ tmp/sockets
+ tmp/cache
+ tmp/pids
+ )
+
+ MYSQL_SOCKET_LOCATIONS = [
+ "/tmp/mysql.sock", # default
+ "/var/run/mysqld/mysqld.sock", # debian/gentoo
+ "/var/tmp/mysql.sock", # freebsd
+ "/var/lib/mysql/mysql.sock", # fedora
+ "/opt/local/lib/mysql/mysql.sock", # fedora
+ "/opt/local/var/run/mysqld/mysqld.sock", # mac + darwinports + mysql
+ "/opt/local/var/run/mysql4/mysqld.sock", # mac + darwinports + mysql4
+ "/opt/local/var/run/mysql5/mysqld.sock", # mac + darwinports + mysql5
+ "/opt/lampp/var/mysql/mysql.sock" # xampp for linux
+ ]
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/controller/USAGE b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/controller/USAGE
new file mode 100644
index 000000000..d4fae60c8
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/controller/USAGE
@@ -0,0 +1,29 @@
+Description:
+ Stubs out a new controller and its views. Pass the controller name, either
+ CamelCased or under_scored, and a list of views as arguments.
+
+ To create a controller within a module, specify the controller name as a
+ path like 'parent_module/controller_name'.
+
+ This generates a controller class in app/controllers, view templates in
+ app/views/controller_name, a helper class in app/helpers, and a functional
+ test suite in test/functional.
+
+Example:
+ `./script/generate controller CreditCard open debit credit close`
+
+ Credit card controller with URLs like /credit_card/debit.
+ Controller: app/controllers/credit_card_controller.rb
+ Views: app/views/credit_card/debit.html.erb [...]
+ Helper: app/helpers/credit_card_helper.rb
+ Test: test/functional/credit_card_controller_test.rb
+
+Modules Example:
+ `./script/generate controller 'admin/credit_card' suspend late_fee`
+
+ Credit card admin controller with URLs /admin/credit_card/suspend.
+ Controller: app/controllers/admin/credit_card_controller.rb
+ Views: app/views/admin/credit_card/debit.html.erb [...]
+ Helper: app/helpers/admin/credit_card_helper.rb
+ Test: test/functional/admin/credit_card_controller_test.rb
+
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/controller/controller_generator.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/controller/controller_generator.rb
new file mode 100644
index 000000000..c37ff4583
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/controller/controller_generator.rb
@@ -0,0 +1,37 @@
+class ControllerGenerator < Rails::Generator::NamedBase
+ def manifest
+ record do |m|
+ # Check for class naming collisions.
+ m.class_collisions class_path, "#{class_name}Controller", "#{class_name}ControllerTest", "#{class_name}Helper"
+
+ # Controller, helper, views, and test directories.
+ m.directory File.join('app/controllers', class_path)
+ m.directory File.join('app/helpers', class_path)
+ m.directory File.join('app/views', class_path, file_name)
+ m.directory File.join('test/functional', class_path)
+
+ # Controller class, functional test, and helper class.
+ m.template 'controller.rb',
+ File.join('app/controllers',
+ class_path,
+ "#{file_name}_controller.rb")
+
+ m.template 'functional_test.rb',
+ File.join('test/functional',
+ class_path,
+ "#{file_name}_controller_test.rb")
+
+ m.template 'helper.rb',
+ File.join('app/helpers',
+ class_path,
+ "#{file_name}_helper.rb")
+
+ # View template for each action.
+ actions.each do |action|
+ path = File.join('app/views', class_path, file_name, "#{action}.html.erb")
+ m.template 'view.html.erb', path,
+ :assigns => { :action => action, :path => path }
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/controller/templates/controller.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/controller/templates/controller.rb
new file mode 100644
index 000000000..da71b5f05
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/controller/templates/controller.rb
@@ -0,0 +1,10 @@
+class <%= class_name %>Controller < ApplicationController
+<% if options[:scaffold] -%>
+ scaffold :<%= singular_name %>
+<% end -%>
+<% for action in actions -%>
+
+ def <%= action %>
+ end
+<% end -%>
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/controller/templates/functional_test.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/controller/templates/functional_test.rb
new file mode 100644
index 000000000..935beafa6
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/controller/templates/functional_test.rb
@@ -0,0 +1,8 @@
+require File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../test_helper'
+
+class <%= class_name %>ControllerTest < ActionController::TestCase
+ # Replace this with your real tests.
+ def test_truth
+ assert true
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/controller/templates/helper.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/controller/templates/helper.rb
new file mode 100644
index 000000000..3fe2ecdc7
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/controller/templates/helper.rb
@@ -0,0 +1,2 @@
+module <%= class_name %>Helper
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/controller/templates/view.html.erb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/controller/templates/view.html.erb
new file mode 100644
index 000000000..ad85431f9
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/controller/templates/view.html.erb
@@ -0,0 +1,2 @@
+<h1><%= class_name %>#<%= action %></h1>
+<p>Find me in <%= path %></p>
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/integration_test/USAGE b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/integration_test/USAGE
new file mode 100644
index 000000000..09e2691f6
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/integration_test/USAGE
@@ -0,0 +1,8 @@
+Description:
+ Stubs out a new integration test. Pass the name of the test, either
+ CamelCased or under_scored, as an argument. The new test class is
+ generated in test/integration/testname_test.rb
+
+Example:
+ `./script/generate integration_test GeneralStories` creates a GeneralStories
+ integration test in test/integration/general_stories_test.rb
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/integration_test/integration_test_generator.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/integration_test/integration_test_generator.rb
new file mode 100644
index 000000000..90fa96938
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/integration_test/integration_test_generator.rb
@@ -0,0 +1,16 @@
+class IntegrationTestGenerator < Rails::Generator::NamedBase
+ default_options :skip_migration => false
+
+ def manifest
+ record do |m|
+ # Check for class naming collisions.
+ m.class_collisions class_path, class_name, "#{class_name}Test"
+
+ # integration test directory
+ m.directory File.join('test/integration', class_path)
+
+ # integration test stub
+ m.template 'integration_test.rb', File.join('test/integration', class_path, "#{file_name}_test.rb")
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/integration_test/templates/integration_test.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/integration_test/templates/integration_test.rb
new file mode 100644
index 000000000..61688aee4
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/integration_test/templates/integration_test.rb
@@ -0,0 +1,10 @@
+require "#{File.dirname(__FILE__)}<%= '/..' * class_nesting_depth %>/../test_helper"
+
+class <%= class_name %>Test < ActionController::IntegrationTest
+ # fixtures :your, :models
+
+ # Replace this with your real tests.
+ def test_truth
+ assert true
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/mailer/USAGE b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/mailer/USAGE
new file mode 100644
index 000000000..61a649ed4
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/mailer/USAGE
@@ -0,0 +1,16 @@
+Description:
+ Stubs out a new mailer and its views. Pass the mailer name, either
+ CamelCased or under_scored, and an optional list of emails as arguments.
+
+ This generates a mailer class in app/models, view templates in
+ app/views/mailer_name, a unit test in test/unit, and fixtures in
+ test/fixtures.
+
+Example:
+ `./script/generate mailer Notifications signup forgot_password invoice`
+
+ creates a Notifications mailer class, views, test, and fixtures:
+ Mailer: app/models/notifications.rb
+ Views: app/views/notifications/signup.erb [...]
+ Test: test/unit/test/unit/notifications_test.rb
+ Fixtures: test/fixtures/notifications/signup [...]
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/mailer/mailer_generator.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/mailer/mailer_generator.rb
new file mode 100644
index 000000000..3ff4f0397
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/mailer/mailer_generator.rb
@@ -0,0 +1,34 @@
+class MailerGenerator < Rails::Generator::NamedBase
+ def manifest
+ record do |m|
+ # Check for class naming collisions.
+ m.class_collisions class_path, class_name, "#{class_name}Test"
+
+ # Mailer, view, test, and fixture directories.
+ m.directory File.join('app/models', class_path)
+ m.directory File.join('app/views', file_path)
+ m.directory File.join('test/unit', class_path)
+ m.directory File.join('test/fixtures', file_path)
+
+ # Mailer class and unit test.
+ m.template "mailer.rb", File.join('app/models',
+ class_path,
+ "#{file_name}.rb")
+ m.template "unit_test.rb", File.join('test/unit',
+ class_path,
+ "#{file_name}_test.rb")
+
+ # View template and fixture for each action.
+ actions.each do |action|
+ relative_path = File.join(file_path, action)
+ view_path = File.join('app/views', "#{relative_path}.erb")
+ fixture_path = File.join('test/fixtures', relative_path)
+
+ m.template "view.erb", view_path,
+ :assigns => { :action => action, :path => view_path }
+ m.template "fixture.erb", fixture_path,
+ :assigns => { :action => action, :path => view_path }
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/mailer/templates/fixture.erb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/mailer/templates/fixture.erb
new file mode 100644
index 000000000..6899257dd
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/mailer/templates/fixture.erb
@@ -0,0 +1,3 @@
+<%= class_name %>#<%= action %>
+
+Find me in <%= path %>
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/mailer/templates/fixture.rhtml b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/mailer/templates/fixture.rhtml
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/mailer/templates/fixture.rhtml
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/mailer/templates/mailer.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/mailer/templates/mailer.rb
new file mode 100644
index 000000000..127495fcb
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/mailer/templates/mailer.rb
@@ -0,0 +1,13 @@
+class <%= class_name %> < ActionMailer::Base
+<% for action in actions -%>
+
+ def <%= action %>(sent_at = Time.now)
+ @subject = '<%= class_name %>#<%= action %>'
+ @body = {}
+ @recipients = ''
+ @from = ''
+ @sent_on = sent_at
+ @headers = {}
+ end
+<% end -%>
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/mailer/templates/unit_test.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/mailer/templates/unit_test.rb
new file mode 100644
index 000000000..dcd020621
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/mailer/templates/unit_test.rb
@@ -0,0 +1,21 @@
+require File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../test_helper'
+
+class <%= class_name %>Test < ActionMailer::TestCase
+ tests <%= class_name %>
+<% for action in actions -%>
+ def test_<%= action %>
+ @expected.subject = '<%= class_name %>#<%= action %>'
+ @expected.body = read_fixture('<%= action %>')
+ @expected.date = Time.now
+
+ assert_equal @expected.encoded, <%= class_name %>.create_<%= action %>(@expected.date).encoded
+ end
+
+<% end -%>
+<% if actions.blank? -%>
+ # replace this with your real tests
+ def test_truth
+ assert true
+ end
+<% end -%>
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/mailer/templates/view.erb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/mailer/templates/view.erb
new file mode 100644
index 000000000..6899257dd
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/mailer/templates/view.erb
@@ -0,0 +1,3 @@
+<%= class_name %>#<%= action %>
+
+Find me in <%= path %>
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/mailer/templates/view.rhtml b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/mailer/templates/view.rhtml
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/mailer/templates/view.rhtml
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/migration/USAGE b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/migration/USAGE
new file mode 100644
index 000000000..3e914a5d7
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/migration/USAGE
@@ -0,0 +1,29 @@
+Description:
+ Stubs out a new database migration. Pass the migration name, either
+ CamelCased or under_scored, and an optional list of attribute pairs as arguments.
+
+ A migration class is generated in db/migrate prefixed by the latest migration number.
+
+ You can name your migration in either of these formats to generate add/remove
+ column lines from supplied attributes: AddColumnsToTable or RemoveColumnsFromTable
+
+Example:
+ `./script/generate migration AddSslFlag`
+
+ With 4 existing migrations, this creates the AddSslFlag migration in
+ db/migrate/005_add_ssl_flag.rb
+
+ `./script/generate migration AddTitleBodyToPost title:string body:text published:boolean`
+
+ This will create the AddTitleBodyToPost in db/migrate/005_add_title_body_to_post.rb with
+ this in the Up migration:
+
+ add_column :posts, :title, :string
+ add_column :posts, :body, :text
+ add_column :posts, :published, :boolean
+
+ And this in the Down migration:
+
+ remove_column :posts, :published
+ remove_column :posts, :body
+ remove_column :posts, :title
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/migration/migration_generator.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/migration/migration_generator.rb
new file mode 100644
index 000000000..acf41e07d
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/migration/migration_generator.rb
@@ -0,0 +1,20 @@
+class MigrationGenerator < Rails::Generator::NamedBase
+ def manifest
+ record do |m|
+ m.migration_template 'migration.rb', 'db/migrate', :assigns => get_local_assigns
+ end
+ end
+
+
+ private
+ def get_local_assigns
+ returning(assigns = {}) do
+ if class_name.underscore =~ /^(add|remove)_.*_(?:to|from)_(.*)/
+ assigns[:migration_action] = $1
+ assigns[:table_name] = $2.pluralize
+ else
+ assigns[:attributes] = []
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/migration/templates/migration.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/migration/templates/migration.rb
new file mode 100644
index 000000000..ca35a4322
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/migration/templates/migration.rb
@@ -0,0 +1,11 @@
+class <%= class_name.underscore.camelize %> < ActiveRecord::Migration
+ def self.up<% attributes.each do |attribute| %>
+ <%= migration_action %>_column :<%= table_name %>, :<%= attribute.name %><% if migration_action == 'add' %>, :<%= attribute.type %><% end -%>
+ <%- end %>
+ end
+
+ def self.down<% attributes.reverse.each do |attribute| %>
+ <%= migration_action == 'add' ? 'remove' : 'add' %>_column :<%= table_name %>, :<%= attribute.name %><% if migration_action == 'remove' %>, :<%= attribute.type %><% end -%>
+ <%- end %>
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/model/USAGE b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/model/USAGE
new file mode 100644
index 000000000..24b03b4d4
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/model/USAGE
@@ -0,0 +1,27 @@
+Description:
+ Stubs out a new model. Pass the model name, either CamelCased or
+ under_scored, and an optional list of attribute pairs as arguments.
+
+ Attribute pairs are column_name:sql_type arguments specifying the
+ model's attributes. Timestamps are added by default, so you don't have to
+ specify them by hand as 'created_at:datetime updated_at:datetime'.
+
+ You don't have to think up every attribute up front, but it helps to
+ sketch out a few so you can start working with the model immediately.
+
+ This generates a model class in app/models, a unit test in test/unit,
+ a test fixture in test/fixtures/singular_name.yml, and a migration in
+ db/migrate.
+
+Examples:
+ `./script/generate model account`
+
+ creates an Account model, test, fixture, and migration:
+ Model: app/models/account.rb
+ Test: test/unit/account_test.rb
+ Fixtures: test/fixtures/accounts.yml
+ Migration: db/migrate/XXX_add_accounts.rb
+
+ `./script/generate model post title:string body:text published:boolean`
+
+ creates a Post model with a string title, text body, and published flag.
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/model/model_generator.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/model/model_generator.rb
new file mode 100644
index 000000000..9be9cad8b
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/model/model_generator.rb
@@ -0,0 +1,45 @@
+class ModelGenerator < Rails::Generator::NamedBase
+ default_options :skip_timestamps => false, :skip_migration => false, :skip_fixture => false
+
+ def manifest
+ record do |m|
+ # Check for class naming collisions.
+ m.class_collisions class_path, class_name, "#{class_name}Test"
+
+ # Model, test, and fixture directories.
+ m.directory File.join('app/models', class_path)
+ m.directory File.join('test/unit', class_path)
+ m.directory File.join('test/fixtures', class_path)
+
+ # Model class, unit test, and fixtures.
+ m.template 'model.rb', File.join('app/models', class_path, "#{file_name}.rb")
+ m.template 'unit_test.rb', File.join('test/unit', class_path, "#{file_name}_test.rb")
+
+ unless options[:skip_fixture]
+ m.template 'fixtures.yml', File.join('test/fixtures', "#{table_name}.yml")
+ end
+
+ unless options[:skip_migration]
+ m.migration_template 'migration.rb', 'db/migrate', :assigns => {
+ :migration_name => "Create#{class_name.pluralize.gsub(/::/, '')}"
+ }, :migration_file_name => "create_#{file_path.gsub(/\//, '_').pluralize}"
+ end
+ end
+ end
+
+ protected
+ def banner
+ "Usage: #{$0} #{spec.name} ModelName [field:type, field:type]"
+ end
+
+ def add_options!(opt)
+ opt.separator ''
+ opt.separator 'Options:'
+ opt.on("--skip-timestamps",
+ "Don't add timestamps to the migration file for this model") { |v| options[:skip_timestamps] = v }
+ opt.on("--skip-migration",
+ "Don't generate a migration file for this model") { |v| options[:skip_migration] = v }
+ opt.on("--skip-fixture",
+ "Don't generation a fixture file for this model") { |v| options[:skip_fixture] = v}
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/model/templates/fixtures.yml b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/model/templates/fixtures.yml
new file mode 100644
index 000000000..c21035113
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/model/templates/fixtures.yml
@@ -0,0 +1,19 @@
+# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
+
+<% unless attributes.empty? -%>
+one:
+<% for attribute in attributes -%>
+ <%= attribute.name %>: <%= attribute.default %>
+<% end -%>
+
+two:
+<% for attribute in attributes -%>
+ <%= attribute.name %>: <%= attribute.default %>
+<% end -%>
+<% else -%>
+# one:
+# column: value
+#
+# two:
+# column: value
+<% end -%>
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/model/templates/migration.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/model/templates/migration.rb
new file mode 100644
index 000000000..382fd1156
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/model/templates/migration.rb
@@ -0,0 +1,16 @@
+class <%= migration_name %> < ActiveRecord::Migration
+ def self.up
+ create_table :<%= table_name %> do |t|
+<% for attribute in attributes -%>
+ t.<%= attribute.type %> :<%= attribute.name %>
+<% end -%>
+<% unless options[:skip_timestamps] %>
+ t.timestamps
+<% end -%>
+ end
+ end
+
+ def self.down
+ drop_table :<%= table_name %>
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/model/templates/model.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/model/templates/model.rb
new file mode 100644
index 000000000..8d4c89e91
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/model/templates/model.rb
@@ -0,0 +1,2 @@
+class <%= class_name %> < ActiveRecord::Base
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/model/templates/unit_test.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/model/templates/unit_test.rb
new file mode 100644
index 000000000..9bb3ca416
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/model/templates/unit_test.rb
@@ -0,0 +1,8 @@
+require File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../test_helper'
+
+class <%= class_name %>Test < ActiveSupport::TestCase
+ # Replace this with your real tests.
+ def test_truth
+ assert true
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/observer/USAGE b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/observer/USAGE
new file mode 100644
index 000000000..a5d744a3c
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/observer/USAGE
@@ -0,0 +1,13 @@
+Description:
+ Stubs out a new observer. Pass the observer name, either CamelCased or
+ under_scored, as an argument.
+
+ The generator creates an observer class in app/models and a unit test in
+ test/unit.
+
+Example:
+ `./script/generate observer Account`
+
+ creates an Account observer and unit test:
+ Observer: app/models/account_observer.rb
+ Test: test/unit/account_observer_test.rb
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/observer/observer_generator.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/observer/observer_generator.rb
new file mode 100644
index 000000000..18fbd32b7
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/observer/observer_generator.rb
@@ -0,0 +1,16 @@
+class ObserverGenerator < Rails::Generator::NamedBase
+ def manifest
+ record do |m|
+ # Check for class naming collisions.
+ m.class_collisions class_path, "#{class_name}Observer", "#{class_name}ObserverTest"
+
+ # Observer, and test directories.
+ m.directory File.join('app/models', class_path)
+ m.directory File.join('test/unit', class_path)
+
+ # Observer class and unit test fixtures.
+ m.template 'observer.rb', File.join('app/models', class_path, "#{file_name}_observer.rb")
+ m.template 'unit_test.rb', File.join('test/unit', class_path, "#{file_name}_observer_test.rb")
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/observer/templates/observer.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/observer/templates/observer.rb
new file mode 100644
index 000000000..b9a300416
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/observer/templates/observer.rb
@@ -0,0 +1,2 @@
+class <%= class_name %>Observer < ActiveRecord::Observer
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/observer/templates/unit_test.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/observer/templates/unit_test.rb
new file mode 100644
index 000000000..b432f04fc
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/observer/templates/unit_test.rb
@@ -0,0 +1,8 @@
+require File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../test_helper'
+
+class <%= class_name %>ObserverTest < Test::Unit::TestCase
+ # Replace this with your real tests.
+ def test_truth
+ assert true
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/USAGE b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/USAGE
new file mode 100644
index 000000000..d2ecfc2d5
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/USAGE
@@ -0,0 +1,25 @@
+Description:
+ Stubs out a new plugin. Pass the plugin name, either CamelCased or
+ under_scored, as an argument. Pass --with-generator to add an example
+ generator also.
+
+ This creates a plugin in vendor/plugins including an init.rb and README
+ as well as standard lib, task, and test directories.
+
+Example:
+ `./script/generate plugin BrowserFilters`
+
+ creates a standard browser_filters plugin:
+ vendor/plugins/browser_filters/README
+ vendor/plugins/browser_filters/init.rb
+ vendor/plugins/browser_filters/install.rb
+ vendor/plugins/browser_filters/lib/browser_filters.rb
+ vendor/plugins/browser_filters/test/browser_filters_test.rb
+ vendor/plugins/browser_filters/tasks/browser_filters_tasks.rake
+
+ ./script/generate plugin BrowserFilters --with-generator
+
+ creates a browser_filters generator also:
+ vendor/plugins/browser_filters/generators/browser_filters/browser_filters_generator.rb
+ vendor/plugins/browser_filters/generators/browser_filters/USAGE
+ vendor/plugins/browser_filters/generators/browser_filters/templates/
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/plugin_generator.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/plugin_generator.rb
new file mode 100644
index 000000000..7a619825a
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/plugin_generator.rb
@@ -0,0 +1,39 @@
+class PluginGenerator < Rails::Generator::NamedBase
+ attr_reader :plugin_path
+
+ def initialize(runtime_args, runtime_options = {})
+ @with_generator = runtime_args.delete("--with-generator")
+ super
+ @plugin_path = "vendor/plugins/#{file_name}"
+ end
+
+ def manifest
+ record do |m|
+ # Check for class naming collisions.
+ m.class_collisions class_path, class_name
+
+ m.directory "#{plugin_path}/lib"
+ m.directory "#{plugin_path}/tasks"
+ m.directory "#{plugin_path}/test"
+
+ m.template 'README', "#{plugin_path}/README"
+ m.template 'MIT-LICENSE', "#{plugin_path}/MIT-LICENSE"
+ m.template 'Rakefile', "#{plugin_path}/Rakefile"
+ m.template 'init.rb', "#{plugin_path}/init.rb"
+ m.template 'install.rb', "#{plugin_path}/install.rb"
+ m.template 'uninstall.rb', "#{plugin_path}/uninstall.rb"
+ m.template 'plugin.rb', "#{plugin_path}/lib/#{file_name}.rb"
+ m.template 'tasks.rake', "#{plugin_path}/tasks/#{file_name}_tasks.rake"
+ m.template 'unit_test.rb', "#{plugin_path}/test/#{file_name}_test.rb"
+
+ if @with_generator
+ m.directory "#{plugin_path}/generators"
+ m.directory "#{plugin_path}/generators/#{file_name}"
+ m.directory "#{plugin_path}/generators/#{file_name}/templates"
+
+ m.template 'generator.rb', "#{plugin_path}/generators/#{file_name}/#{file_name}_generator.rb"
+ m.template 'USAGE', "#{plugin_path}/generators/#{file_name}/USAGE"
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/MIT-LICENSE b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/MIT-LICENSE
new file mode 100644
index 000000000..8717df053
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/MIT-LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) <%= Date.today.year %> [name of plugin creator]
+
+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.
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/README b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/README
new file mode 100644
index 000000000..702db07cb
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/README
@@ -0,0 +1,13 @@
+<%= class_name %>
+<%= "=" * class_name.size %>
+
+Introduction goes here.
+
+
+Example
+=======
+
+Example goes here.
+
+
+Copyright (c) <%= Date.today.year %> [name of plugin creator], released under the MIT license
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/Rakefile b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/Rakefile
new file mode 100755
index 000000000..1824fb10f
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/Rakefile
@@ -0,0 +1,22 @@
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+
+desc 'Default: run unit tests.'
+task :default => :test
+
+desc 'Test the <%= file_name %> plugin.'
+Rake::TestTask.new(:test) do |t|
+ t.libs << 'lib'
+ t.pattern = 'test/**/*_test.rb'
+ t.verbose = true
+end
+
+desc 'Generate documentation for the <%= file_name %> plugin.'
+Rake::RDocTask.new(:rdoc) do |rdoc|
+ rdoc.rdoc_dir = 'rdoc'
+ rdoc.title = '<%= class_name %>'
+ rdoc.options << '--line-numbers' << '--inline-source'
+ rdoc.rdoc_files.include('README')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/USAGE b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/USAGE
new file mode 100644
index 000000000..ea9f4f12c
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/USAGE
@@ -0,0 +1,8 @@
+Description:
+ Explain the generator
+
+Example:
+ ./script/generate <%= file_name %> Thing
+
+ This will create:
+ what/will/it/create
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/generator.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/generator.rb
new file mode 100644
index 000000000..3e800df6c
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/generator.rb
@@ -0,0 +1,8 @@
+class <%= class_name %>Generator < Rails::Generator::NamedBase
+ def manifest
+ record do |m|
+ # m.directory "lib"
+ # m.template 'README', "README"
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/init.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/init.rb
new file mode 100644
index 000000000..3c19a743c
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/init.rb
@@ -0,0 +1 @@
+# Include hook code here
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/install.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/install.rb
new file mode 100644
index 000000000..f7732d379
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/install.rb
@@ -0,0 +1 @@
+# Install hook code here
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/plugin.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/plugin.rb
new file mode 100644
index 000000000..d8d908a95
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/plugin.rb
@@ -0,0 +1 @@
+# <%= class_name %>
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/tasks.rake b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/tasks.rake
new file mode 100644
index 000000000..72920a9d3
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/tasks.rake
@@ -0,0 +1,4 @@
+# desc "Explaining what the task does"
+# task :<%= file_name %> do
+# # Task goes here
+# end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/uninstall.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/uninstall.rb
new file mode 100644
index 000000000..973833346
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/uninstall.rb
@@ -0,0 +1 @@
+# Uninstall hook code here
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/unit_test.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/unit_test.rb
new file mode 100644
index 000000000..9028b84b7
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/plugin/templates/unit_test.rb
@@ -0,0 +1,8 @@
+require 'test/unit'
+
+class <%= class_name %>Test < Test::Unit::TestCase
+ # Replace this with your real tests.
+ def test_this_plugin
+ flunk
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/resource/USAGE b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/resource/USAGE
new file mode 100644
index 000000000..83cc9d765
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/resource/USAGE
@@ -0,0 +1,23 @@
+Description:
+ Stubs out a new resource including an empty model and controller suitable
+ for a restful, resource-oriented application. Pass the singular model name,
+ either CamelCased or under_scored, as the first argument, and an optional
+ list of attribute pairs.
+
+ Attribute pairs are column_name:sql_type arguments specifying the
+ model's attributes. Timestamps are added by default, so you don't have to
+ specify them by hand as 'created_at:datetime updated_at:datetime'.
+
+ You don't have to think up every attribute up front, but it helps to
+ sketch out a few so you can start working with the resource immediately.
+
+ This creates a model, controller, tests and fixtures for both, and the
+ corresponding map.resources declaration in config/routes.rb
+
+ Unlike the scaffold generator, the resource generator does not create
+ views or add any methods to the generated controller.
+
+Examples:
+ `./script/generate resource post` # no attributes
+ `./script/generate resource post title:string body:text published:boolean`
+ `./script/generate resource purchase order_id:integer amount:decimal`
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/resource/resource_generator.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/resource/resource_generator.rb
new file mode 100644
index 000000000..d5491ece3
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/resource/resource_generator.rb
@@ -0,0 +1,74 @@
+class ResourceGenerator < Rails::Generator::NamedBase
+ default_options :skip_timestamps => false, :skip_migration => false
+
+ attr_reader :controller_name,
+ :controller_class_path,
+ :controller_file_path,
+ :controller_class_nesting,
+ :controller_class_nesting_depth,
+ :controller_class_name,
+ :controller_singular_name,
+ :controller_plural_name
+ alias_method :controller_file_name, :controller_singular_name
+ alias_method :controller_table_name, :controller_plural_name
+
+ def initialize(runtime_args, runtime_options = {})
+ super
+
+ @controller_name = @name.pluralize
+
+ base_name, @controller_class_path, @controller_file_path, @controller_class_nesting, @controller_class_nesting_depth = extract_modules(@controller_name)
+ @controller_class_name_without_nesting, @controller_singular_name, @controller_plural_name = inflect_names(base_name)
+
+ if @controller_class_nesting.empty?
+ @controller_class_name = @controller_class_name_without_nesting
+ else
+ @controller_class_name = "#{@controller_class_nesting}::#{@controller_class_name_without_nesting}"
+ end
+ end
+
+ def manifest
+ record do |m|
+ # Check for class naming collisions.
+ m.class_collisions(controller_class_path, "#{controller_class_name}Controller", "#{controller_class_name}Helper")
+ m.class_collisions(class_path, "#{class_name}")
+
+ # Controller, helper, views, and test directories.
+ m.directory(File.join('app/models', class_path))
+ m.directory(File.join('app/controllers', controller_class_path))
+ m.directory(File.join('app/helpers', controller_class_path))
+ m.directory(File.join('app/views', controller_class_path, controller_file_name))
+ m.directory(File.join('test/functional', controller_class_path))
+ m.directory(File.join('test/unit', class_path))
+
+ m.dependency 'model', [name] + @args, :collision => :skip
+
+ m.template(
+ 'controller.rb', File.join('app/controllers', controller_class_path, "#{controller_file_name}_controller.rb")
+ )
+
+ m.template('functional_test.rb', File.join('test/functional', controller_class_path, "#{controller_file_name}_controller_test.rb"))
+ m.template('helper.rb', File.join('app/helpers', controller_class_path, "#{controller_file_name}_helper.rb"))
+
+ m.route_resources controller_file_name
+ end
+ end
+
+ protected
+ def banner
+ "Usage: #{$0} resource ModelName [field:type, field:type]"
+ end
+
+ def add_options!(opt)
+ opt.separator ''
+ opt.separator 'Options:'
+ opt.on("--skip-timestamps",
+ "Don't add timestamps to the migration file for this model") { |v| options[:skip_timestamps] = v }
+ opt.on("--skip-migration",
+ "Don't generate a migration file for this model") { |v| options[:skip_migration] = v }
+ end
+
+ def model_name
+ class_name.demodulize
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/resource/templates/controller.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/resource/templates/controller.rb
new file mode 100644
index 000000000..765a94269
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/resource/templates/controller.rb
@@ -0,0 +1,2 @@
+class <%= controller_class_name %>Controller < ApplicationController
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/resource/templates/functional_test.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/resource/templates/functional_test.rb
new file mode 100644
index 000000000..19363a82d
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/resource/templates/functional_test.rb
@@ -0,0 +1,8 @@
+require File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../test_helper'
+
+class <%= controller_class_name %>ControllerTest < ActionController::TestCase
+ # Replace this with your real tests.
+ def test_truth
+ assert true
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/resource/templates/helper.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/resource/templates/helper.rb
new file mode 100644
index 000000000..9bd821b1b
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/resource/templates/helper.rb
@@ -0,0 +1,2 @@
+module <%= controller_class_name %>Helper
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/USAGE b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/USAGE
new file mode 100644
index 000000000..a0e4baea0
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/USAGE
@@ -0,0 +1,25 @@
+Description:
+ Scaffolds an entire resource, from model and migration to controller and
+ views, along with a full test suite. The resource is ready to use as a
+ starting point for your restful, resource-oriented application.
+
+ Pass the name of the model, either CamelCased or under_scored, as the first
+ argument, and an optional list of attribute pairs.
+
+ Attribute pairs are column_name:sql_type arguments specifying the
+ model's attributes. Timestamps are added by default, so you don't have to
+ specify them by hand as 'created_at:datetime updated_at:datetime'.
+
+ You don't have to think up every attribute up front, but it helps to
+ sketch out a few so you can start working with the resource immediately.
+
+ For example, `scaffold post title:string body:text published:boolean`
+ gives you a model with those three attributes, a controller that handles
+ the create/show/update/destroy, forms to create and edit your posts, and
+ an index that lists them all, as well as a map.resources :posts
+ declaration in config/routes.rb.
+
+Examples:
+ `./script/generate scaffold post` # no attributes, view will be anemic
+ `./script/generate scaffold post title:string body:text published:boolean`
+ `./script/generate scaffold purchase order_id:integer amount:decimal`
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb
new file mode 100644
index 000000000..c9ce49a6f
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb
@@ -0,0 +1,92 @@
+class ScaffoldGenerator < Rails::Generator::NamedBase
+ default_options :skip_timestamps => false, :skip_migration => false
+
+ attr_reader :controller_name,
+ :controller_class_path,
+ :controller_file_path,
+ :controller_class_nesting,
+ :controller_class_nesting_depth,
+ :controller_class_name,
+ :controller_underscore_name,
+ :controller_singular_name,
+ :controller_plural_name
+ alias_method :controller_file_name, :controller_underscore_name
+ alias_method :controller_table_name, :controller_plural_name
+
+ def initialize(runtime_args, runtime_options = {})
+ super
+
+ @controller_name = @name.pluralize
+
+ base_name, @controller_class_path, @controller_file_path, @controller_class_nesting, @controller_class_nesting_depth = extract_modules(@controller_name)
+ @controller_class_name_without_nesting, @controller_underscore_name, @controller_plural_name = inflect_names(base_name)
+ @controller_singular_name=base_name.singularize
+ if @controller_class_nesting.empty?
+ @controller_class_name = @controller_class_name_without_nesting
+ else
+ @controller_class_name = "#{@controller_class_nesting}::#{@controller_class_name_without_nesting}"
+ end
+ end
+
+ def manifest
+ record do |m|
+ # Check for class naming collisions.
+ m.class_collisions(controller_class_path, "#{controller_class_name}Controller", "#{controller_class_name}Helper")
+ m.class_collisions(class_path, "#{class_name}")
+
+ # Controller, helper, views, and test directories.
+ m.directory(File.join('app/models', class_path))
+ m.directory(File.join('app/controllers', controller_class_path))
+ m.directory(File.join('app/helpers', controller_class_path))
+ m.directory(File.join('app/views', controller_class_path, controller_file_name))
+ m.directory(File.join('app/views/layouts', controller_class_path))
+ m.directory(File.join('test/functional', controller_class_path))
+ m.directory(File.join('test/unit', class_path))
+
+ for action in scaffold_views
+ m.template(
+ "view_#{action}.html.erb",
+ File.join('app/views', controller_class_path, controller_file_name, "#{action}.html.erb")
+ )
+ end
+
+ # Layout and stylesheet.
+ m.template('layout.html.erb', File.join('app/views/layouts', controller_class_path, "#{controller_file_name}.html.erb"))
+ m.template('style.css', 'public/stylesheets/scaffold.css')
+
+ m.dependency 'model', [name] + @args, :collision => :skip
+
+ m.template(
+ 'controller.rb', File.join('app/controllers', controller_class_path, "#{controller_file_name}_controller.rb")
+ )
+
+ m.template('functional_test.rb', File.join('test/functional', controller_class_path, "#{controller_file_name}_controller_test.rb"))
+ m.template('helper.rb', File.join('app/helpers', controller_class_path, "#{controller_file_name}_helper.rb"))
+
+ m.route_resources controller_file_name
+ end
+ end
+
+ protected
+ # Override with your own usage banner.
+ def banner
+ "Usage: #{$0} scaffold ModelName [field:type, field:type]"
+ end
+
+ def add_options!(opt)
+ opt.separator ''
+ opt.separator 'Options:'
+ opt.on("--skip-timestamps",
+ "Don't add timestamps to the migration file for this model") { |v| options[:skip_timestamps] = v }
+ opt.on("--skip-migration",
+ "Don't generate a migration file for this model") { |v| options[:skip_migration] = v }
+ end
+
+ def scaffold_views
+ %w[ index show new edit ]
+ end
+
+ def model_name
+ class_name.demodulize
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/controller.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/controller.rb
new file mode 100644
index 000000000..cbfd88f3b
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/controller.rb
@@ -0,0 +1,85 @@
+class <%= controller_class_name %>Controller < ApplicationController
+ # GET /<%= table_name %>
+ # GET /<%= table_name %>.xml
+ def index
+ @<%= table_name %> = <%= class_name %>.find(:all)
+
+ respond_to do |format|
+ format.html # index.html.erb
+ format.xml { render :xml => @<%= table_name %> }
+ end
+ end
+
+ # GET /<%= table_name %>/1
+ # GET /<%= table_name %>/1.xml
+ def show
+ @<%= file_name %> = <%= class_name %>.find(params[:id])
+
+ respond_to do |format|
+ format.html # show.html.erb
+ format.xml { render :xml => @<%= file_name %> }
+ end
+ end
+
+ # GET /<%= table_name %>/new
+ # GET /<%= table_name %>/new.xml
+ def new
+ @<%= file_name %> = <%= class_name %>.new
+
+ respond_to do |format|
+ format.html # new.html.erb
+ format.xml { render :xml => @<%= file_name %> }
+ end
+ end
+
+ # GET /<%= table_name %>/1/edit
+ def edit
+ @<%= file_name %> = <%= class_name %>.find(params[:id])
+ end
+
+ # POST /<%= table_name %>
+ # POST /<%= table_name %>.xml
+ def create
+ @<%= file_name %> = <%= class_name %>.new(params[:<%= file_name %>])
+
+ respond_to do |format|
+ if @<%= file_name %>.save
+ flash[:notice] = '<%= class_name %> was successfully created.'
+ format.html { redirect_to(@<%= file_name %>) }
+ format.xml { render :xml => @<%= file_name %>, :status => :created, :location => @<%= file_name %> }
+ else
+ format.html { render :action => "new" }
+ format.xml { render :xml => @<%= file_name %>.errors, :status => :unprocessable_entity }
+ end
+ end
+ end
+
+ # PUT /<%= table_name %>/1
+ # PUT /<%= table_name %>/1.xml
+ def update
+ @<%= file_name %> = <%= class_name %>.find(params[:id])
+
+ respond_to do |format|
+ if @<%= file_name %>.update_attributes(params[:<%= file_name %>])
+ flash[:notice] = '<%= class_name %> was successfully updated.'
+ format.html { redirect_to(@<%= file_name %>) }
+ format.xml { head :ok }
+ else
+ format.html { render :action => "edit" }
+ format.xml { render :xml => @<%= file_name %>.errors, :status => :unprocessable_entity }
+ end
+ end
+ end
+
+ # DELETE /<%= table_name %>/1
+ # DELETE /<%= table_name %>/1.xml
+ def destroy
+ @<%= file_name %> = <%= class_name %>.find(params[:id])
+ @<%= file_name %>.destroy
+
+ respond_to do |format|
+ format.html { redirect_to(<%= table_name %>_url) }
+ format.xml { head :ok }
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb
new file mode 100644
index 000000000..2b1f6520d
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb
@@ -0,0 +1,45 @@
+require File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../test_helper'
+
+class <%= controller_class_name %>ControllerTest < ActionController::TestCase
+ def test_should_get_index
+ get :index
+ assert_response :success
+ assert_not_nil assigns(:<%= table_name %>)
+ end
+
+ def test_should_get_new
+ get :new
+ assert_response :success
+ end
+
+ def test_should_create_<%= file_name %>
+ assert_difference('<%= class_name %>.count') do
+ post :create, :<%= file_name %> => { }
+ end
+
+ assert_redirected_to <%= file_name %>_path(assigns(:<%= file_name %>))
+ end
+
+ def test_should_show_<%= file_name %>
+ get :show, :id => <%= table_name %>(:one).id
+ assert_response :success
+ end
+
+ def test_should_get_edit
+ get :edit, :id => <%= table_name %>(:one).id
+ assert_response :success
+ end
+
+ def test_should_update_<%= file_name %>
+ put :update, :id => <%= table_name %>(:one).id, :<%= file_name %> => { }
+ assert_redirected_to <%= file_name %>_path(assigns(:<%= file_name %>))
+ end
+
+ def test_should_destroy_<%= file_name %>
+ assert_difference('<%= class_name %>.count', -1) do
+ delete :destroy, :id => <%= table_name %>(:one).id
+ end
+
+ assert_redirected_to <%= table_name %>_path
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/helper.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/helper.rb
new file mode 100644
index 000000000..9bd821b1b
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/helper.rb
@@ -0,0 +1,2 @@
+module <%= controller_class_name %>Helper
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/layout.html.erb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/layout.html.erb
new file mode 100644
index 000000000..5c1f30423
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/layout.html.erb
@@ -0,0 +1,17 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
+ <title><%= controller_class_name %>: <%%= controller.action_name %></title>
+ <%%= stylesheet_link_tag 'scaffold' %>
+</head>
+<body>
+
+<p style="color: green"><%%= flash[:notice] %></p>
+
+<%%= yield %>
+
+</body>
+</html>
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/style.css b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/style.css
new file mode 100644
index 000000000..879e85b36
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/style.css
@@ -0,0 +1,74 @@
+body { background-color: #fff; color: #333; }
+
+body, p, ol, ul, td {
+ font-family: verdana, arial, helvetica, sans-serif;
+ font-size: 13px;
+ line-height: 18px;
+}
+
+pre {
+ background-color: #eee;
+ padding: 10px;
+ font-size: 11px;
+}
+
+a { color: #000; }
+a:visited { color: #666; }
+a:hover { color: #fff; background-color:#000; }
+
+.fieldWithErrors {
+ padding: 2px;
+ background-color: red;
+ display: table;
+}
+
+#errorExplanation {
+ width: 400px;
+ border: 2px solid red;
+ padding: 7px;
+ padding-bottom: 12px;
+ margin-bottom: 20px;
+ background-color: #f0f0f0;
+}
+
+#errorExplanation h2 {
+ text-align: left;
+ font-weight: bold;
+ padding: 5px 5px 5px 15px;
+ font-size: 12px;
+ margin: -7px;
+ background-color: #c00;
+ color: #fff;
+}
+
+#errorExplanation p {
+ color: #333;
+ margin-bottom: 0;
+ padding: 5px;
+}
+
+#errorExplanation ul li {
+ font-size: 12px;
+ list-style: square;
+}
+
+div.uploadStatus {
+ margin: 5px;
+}
+
+div.progressBar {
+ margin: 5px;
+}
+
+div.progressBar div.border {
+ background-color: #fff;
+ border: 1px solid gray;
+ width: 100%;
+}
+
+div.progressBar div.background {
+ background-color: #333;
+ height: 18px;
+ width: 0%;
+}
+
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/view_edit.html.erb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/view_edit.html.erb
new file mode 100644
index 000000000..8a65b50db
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/view_edit.html.erb
@@ -0,0 +1,19 @@
+<h1>Editing <%= singular_name %></h1>
+
+<%%= error_messages_for :<%= singular_name %> %>
+
+<%% form_for(@<%= singular_name %>) do |f| %>
+<% for attribute in attributes -%>
+ <p>
+ <b><%= attribute.column.human_name %></b><br />
+ <%%= f.<%= attribute.field_type %> :<%= attribute.name %> %>
+ </p>
+
+<% end -%>
+ <p>
+ <%%= f.submit "Update" %>
+ </p>
+<%% end %>
+
+<%%= link_to 'Show', @<%= singular_name %> %> |
+<%%= link_to 'Back', <%= plural_name %>_path %>
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/view_index.html.erb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/view_index.html.erb
new file mode 100644
index 000000000..e89757e3e
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/view_index.html.erb
@@ -0,0 +1,24 @@
+<h1>Listing <%= plural_name %></h1>
+
+<table>
+ <tr>
+<% for attribute in attributes -%>
+ <th><%= attribute.column.human_name %></th>
+<% end -%>
+ </tr>
+
+<%% for <%= singular_name %> in @<%= plural_name %> %>
+ <tr>
+<% for attribute in attributes -%>
+ <td><%%=h <%= singular_name %>.<%= attribute.name %> %></td>
+<% end -%>
+ <td><%%= link_to 'Show', <%= singular_name %> %></td>
+ <td><%%= link_to 'Edit', edit_<%= singular_name %>_path(<%= singular_name %>) %></td>
+ <td><%%= link_to 'Destroy', <%= singular_name %>, :confirm => 'Are you sure?', :method => :delete %></td>
+ </tr>
+<%% end %>
+</table>
+
+<br />
+
+<%%= link_to 'New <%= singular_name %>', new_<%= singular_name %>_path %>
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/view_new.html.erb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/view_new.html.erb
new file mode 100644
index 000000000..96f59900b
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/view_new.html.erb
@@ -0,0 +1,18 @@
+<h1>New <%= singular_name %></h1>
+
+<%%= error_messages_for :<%= singular_name %> %>
+
+<%% form_for(@<%= singular_name %>) do |f| %>
+<% for attribute in attributes -%>
+ <p>
+ <b><%= attribute.column.human_name %></b><br />
+ <%%= f.<%= attribute.field_type %> :<%= attribute.name %> %>
+ </p>
+
+<% end -%>
+ <p>
+ <%%= f.submit "Create" %>
+ </p>
+<%% end %>
+
+<%%= link_to 'Back', <%= plural_name %>_path %>
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/view_show.html.erb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/view_show.html.erb
new file mode 100644
index 000000000..9b6b11b02
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/scaffold/templates/view_show.html.erb
@@ -0,0 +1,10 @@
+<% for attribute in attributes -%>
+<p>
+ <b><%= attribute.column.human_name %>:</b>
+ <%%=h @<%= singular_name %>.<%= attribute.name %> %>
+</p>
+
+<% end -%>
+
+<%%= link_to 'Edit', edit_<%= singular_name %>_path(@<%= singular_name %>) %> |
+<%%= link_to 'Back', <%= plural_name %>_path %>
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/session_migration/USAGE b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/session_migration/USAGE
new file mode 100644
index 000000000..87117a3cb
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/session_migration/USAGE
@@ -0,0 +1,10 @@
+Description:
+ Creates a migration to add the sessions table used by the Active Record
+ session store. Pass the migration name, either CamelCased or under_scored,
+ as an argument.
+
+Example:
+ `./script/generate session_migration CreateSessionTable`
+
+ With 4 existing migrations, this creates the AddSessionTable migration
+ in db/migrate/005_add_session_table.rb
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/session_migration/session_migration_generator.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/session_migration/session_migration_generator.rb
new file mode 100644
index 000000000..2e177033a
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/session_migration/session_migration_generator.rb
@@ -0,0 +1,18 @@
+class SessionMigrationGenerator < Rails::Generator::NamedBase
+ def initialize(runtime_args, runtime_options = {})
+ runtime_args << 'add_session_table' if runtime_args.empty?
+ super
+ end
+
+ def manifest
+ record do |m|
+ m.migration_template 'migration.rb', 'db/migrate',
+ :assigns => { :session_table_name => default_session_table_name }
+ end
+ end
+
+ protected
+ def default_session_table_name
+ ActiveRecord::Base.pluralize_table_names ? 'session'.pluralize : 'session'
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/session_migration/templates/migration.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/session_migration/templates/migration.rb
new file mode 100644
index 000000000..ca220a5f2
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/generators/components/session_migration/templates/migration.rb
@@ -0,0 +1,16 @@
+class <%= class_name %> < ActiveRecord::Migration
+ def self.up
+ create_table :<%= session_table_name %> do |t|
+ t.string :session_id, :null => false
+ t.text :data
+ t.timestamps
+ end
+
+ add_index :<%= session_table_name %>, :session_id
+ add_index :<%= session_table_name %>, :updated_at
+ end
+
+ def self.down
+ drop_table :<%= session_table_name %>
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/lookup.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/lookup.rb
new file mode 100644
index 000000000..598cb79e7
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/lookup.rb
@@ -0,0 +1,244 @@
+require File.dirname(__FILE__) + '/spec'
+
+class Object
+ class << self
+ # Lookup missing generators using const_missing. This allows any
+ # generator to reference another without having to know its location:
+ # RubyGems, ~/.rails/generators, and RAILS_ROOT/generators.
+ def lookup_missing_generator(class_id)
+ if md = /(.+)Generator$/.match(class_id.to_s)
+ name = md.captures.first.demodulize.underscore
+ Rails::Generator::Base.lookup(name).klass
+ else
+ const_missing_before_generators(class_id)
+ end
+ end
+
+ unless respond_to?(:const_missing_before_generators)
+ alias_method :const_missing_before_generators, :const_missing
+ alias_method :const_missing, :lookup_missing_generator
+ end
+ end
+end
+
+# User home directory lookup adapted from RubyGems.
+def Dir.user_home
+ if ENV['HOME']
+ ENV['HOME']
+ elsif ENV['USERPROFILE']
+ ENV['USERPROFILE']
+ elsif ENV['HOMEDRIVE'] and ENV['HOMEPATH']
+ "#{ENV['HOMEDRIVE']}:#{ENV['HOMEPATH']}"
+ else
+ File.expand_path '~'
+ end
+end
+
+
+module Rails
+ module Generator
+
+ # Generator lookup is managed by a list of sources which return specs
+ # describing where to find and how to create generators. This module
+ # provides class methods for manipulating the source list and looking up
+ # generator specs, and an #instance wrapper for quickly instantiating
+ # generators by name.
+ #
+ # A spec is not a generator: it's a description of where to find
+ # the generator and how to create it. A source is anything that
+ # yields generators from #each. PathSource and GemGeneratorSource are provided.
+ module Lookup
+ def self.included(base)
+ base.extend(ClassMethods)
+ base.use_component_sources!
+ end
+
+ # Convenience method to instantiate another generator.
+ def instance(generator_name, args, runtime_options = {})
+ self.class.instance(generator_name, args, runtime_options)
+ end
+
+ module ClassMethods
+ # The list of sources where we look, in order, for generators.
+ def sources
+ read_inheritable_attribute(:sources) or use_component_sources!
+ end
+
+ # Add a source to the end of the list.
+ def append_sources(*args)
+ sources.concat(args.flatten)
+ invalidate_cache!
+ end
+
+ # Add a source to the beginning of the list.
+ def prepend_sources(*args)
+ write_inheritable_array(:sources, args.flatten + sources)
+ invalidate_cache!
+ end
+
+ # Reset the source list.
+ def reset_sources
+ write_inheritable_attribute(:sources, [])
+ invalidate_cache!
+ end
+
+ # Use application generators (app, ?).
+ def use_application_sources!
+ reset_sources
+ sources << PathSource.new(:builtin, "#{File.dirname(__FILE__)}/generators/applications")
+ end
+
+ # Use component generators (model, controller, etc).
+ # 1. Rails application. If RAILS_ROOT is defined we know we're
+ # generating in the context of a Rails application, so search
+ # RAILS_ROOT/generators.
+ # 2. Look in plugins, either for generators/ or rails_generators/
+ # directories within each plugin
+ # 3. User home directory. Search ~/.rails/generators.
+ # 4. RubyGems. Search for gems named *_generator, and look for
+ # generators within any RubyGem's
+ # /rails_generators/<generator_name>_generator.rb file.
+ # 5. Builtins. Model, controller, mailer, scaffold, and so on.
+ def use_component_sources!
+ reset_sources
+ if defined? ::RAILS_ROOT
+ sources << PathSource.new(:lib, "#{::RAILS_ROOT}/lib/generators")
+ sources << PathSource.new(:vendor, "#{::RAILS_ROOT}/vendor/generators")
+ sources << PathSource.new(:plugins, "#{::RAILS_ROOT}/vendor/plugins/*/**/generators")
+ sources << PathSource.new(:plugins, "#{::RAILS_ROOT}/vendor/plugins/*/**/rails_generators")
+ end
+ sources << PathSource.new(:user, "#{Dir.user_home}/.rails/generators")
+ if Object.const_defined?(:Gem)
+ sources << GemGeneratorSource.new
+ sources << GemPathSource.new
+ end
+ sources << PathSource.new(:builtin, "#{File.dirname(__FILE__)}/generators/components")
+ end
+
+ # Lookup knows how to find generators' Specs from a list of Sources.
+ # Searches the sources, in order, for the first matching name.
+ def lookup(generator_name)
+ @found ||= {}
+ generator_name = generator_name.to_s.downcase
+ @found[generator_name] ||= cache.find { |spec| spec.name == generator_name }
+ unless @found[generator_name]
+ chars = generator_name.scan(/./).map{|c|"#{c}.*?"}
+ rx = /^#{chars}$/
+ gns = cache.select{|spec| spec.name =~ rx }
+ @found[generator_name] ||= gns.first if gns.length == 1
+ raise GeneratorError, "Pattern '#{generator_name}' matches more than one generator: #{gns.map{|sp|sp.name}.join(', ')}" if gns.length > 1
+ end
+ @found[generator_name] or raise GeneratorError, "Couldn't find '#{generator_name}' generator"
+ end
+
+ # Convenience method to lookup and instantiate a generator.
+ def instance(generator_name, args = [], runtime_options = {})
+ lookup(generator_name).klass.new(args, full_options(runtime_options))
+ end
+
+ private
+ # Lookup and cache every generator from the source list.
+ def cache
+ @cache ||= sources.inject([]) { |cache, source| cache + source.map }
+ end
+
+ # Clear the cache whenever the source list changes.
+ def invalidate_cache!
+ @cache = nil
+ end
+ end
+ end
+
+ # Sources enumerate (yield from #each) generator specs which describe
+ # where to find and how to create generators. Enumerable is mixed in so,
+ # for example, source.collect will retrieve every generator.
+ # Sources may be assigned a label to distinguish them.
+ class Source
+ include Enumerable
+
+ attr_reader :label
+ def initialize(label)
+ @label = label
+ end
+
+ # The each method must be implemented in subclasses.
+ # The base implementation raises an error.
+ def each
+ raise NotImplementedError
+ end
+
+ # Return a convenient sorted list of all generator names.
+ def names
+ map { |spec| spec.name }.sort
+ end
+ end
+
+
+ # PathSource looks for generators in a filesystem directory.
+ class PathSource < Source
+ attr_reader :path
+
+ def initialize(label, path)
+ super label
+ @path = path
+ end
+
+ # Yield each eligible subdirectory.
+ def each
+ Dir["#{path}/[a-z]*"].each do |dir|
+ if File.directory?(dir)
+ yield Spec.new(File.basename(dir), dir, label)
+ end
+ end
+ end
+ end
+
+ class AbstractGemSource < Source
+ def initialize
+ super :RubyGems
+ end
+ end
+
+ # GemGeneratorSource hits the mines to quarry for generators. The latest versions
+ # of gems named *_generator are selected.
+ class GemGeneratorSource < AbstractGemSource
+ # Yield latest versions of generator gems.
+ def each
+ Gem::cache.search(/_generator$/).inject({}) { |latest, gem|
+ hem = latest[gem.name]
+ latest[gem.name] = gem if hem.nil? or gem.version > hem.version
+ latest
+ }.values.each { |gem|
+ yield Spec.new(gem.name.sub(/_generator$/, ''), gem.full_gem_path, label)
+ }
+ end
+ end
+
+ # GemPathSource looks for generators within any RubyGem's /rails_generators/<generator_name>_generator.rb file.
+ class GemPathSource < AbstractGemSource
+ # Yield each generator within rails_generator subdirectories.
+ def each
+ generator_full_paths.each do |generator|
+ yield Spec.new(File.basename(generator).sub(/_generator.rb$/, ''), File.dirname(generator), label)
+ end
+ end
+
+ private
+ def generator_full_paths
+ @generator_full_paths ||=
+ Gem::cache.inject({}) do |latest, name_gem|
+ name, gem = name_gem
+ hem = latest[gem.name]
+ latest[gem.name] = gem if hem.nil? or gem.version > hem.version
+ latest
+ end.values.inject([]) do |mem, gem|
+ Dir[gem.full_gem_path + '/{rails_,}generators/**/*_generator.rb'].each do |generator|
+ mem << generator
+ end
+ mem
+ end
+ end
+ end
+
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/manifest.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/manifest.rb
new file mode 100644
index 000000000..702effa76
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/manifest.rb
@@ -0,0 +1,53 @@
+module Rails
+ module Generator
+
+ # Manifest captures the actions a generator performs. Instantiate
+ # a manifest with an optional target object, hammer it with actions,
+ # then replay or rewind on the object of your choice.
+ #
+ # Example:
+ # manifest = Manifest.new { |m|
+ # m.make_directory '/foo'
+ # m.create_file '/foo/bar.txt'
+ # }
+ # manifest.replay(creator)
+ # manifest.rewind(destroyer)
+ class Manifest
+ attr_reader :target
+
+ # Take a default action target. Yield self if block given.
+ def initialize(target = nil)
+ @target, @actions = target, []
+ yield self if block_given?
+ end
+
+ # Record an action.
+ def method_missing(action, *args, &block)
+ @actions << [action, args, block]
+ end
+
+ # Replay recorded actions.
+ def replay(target = nil)
+ send_actions(target || @target, @actions)
+ end
+
+ # Rewind recorded actions.
+ def rewind(target = nil)
+ send_actions(target || @target, @actions.reverse)
+ end
+
+ # Erase recorded actions.
+ def erase
+ @actions = []
+ end
+
+ private
+ def send_actions(target, actions)
+ actions.each do |method, args, block|
+ target.send(method, *args, &block)
+ end
+ end
+ end
+
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/options.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/options.rb
new file mode 100644
index 000000000..042e05107
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/options.rb
@@ -0,0 +1,143 @@
+require 'optparse'
+
+module Rails
+ module Generator
+ module Options
+ def self.included(base)
+ base.extend(ClassMethods)
+ class << base
+ if respond_to?(:inherited)
+ alias_method :inherited_without_options, :inherited
+ end
+ alias_method :inherited, :inherited_with_options
+ end
+ end
+
+ module ClassMethods
+ def inherited_with_options(sub)
+ inherited_without_options(sub) if respond_to?(:inherited_without_options)
+ sub.extend(Rails::Generator::Options::ClassMethods)
+ end
+
+ def mandatory_options(options = nil)
+ if options
+ write_inheritable_attribute(:mandatory_options, options)
+ else
+ read_inheritable_attribute(:mandatory_options) or write_inheritable_attribute(:mandatory_options, {})
+ end
+ end
+
+ def default_options(options = nil)
+ if options
+ write_inheritable_attribute(:default_options, options)
+ else
+ read_inheritable_attribute(:default_options) or write_inheritable_attribute(:default_options, {})
+ end
+ end
+
+ # Merge together our class options. In increasing precedence:
+ # default_options (class default options)
+ # runtime_options (provided as argument)
+ # mandatory_options (class mandatory options)
+ def full_options(runtime_options = {})
+ default_options.merge(runtime_options).merge(mandatory_options)
+ end
+
+ end
+
+ # Each instance has an options hash that's populated by #parse.
+ def options
+ @options ||= {}
+ end
+ attr_writer :options
+
+ protected
+ # Convenient access to class mandatory options.
+ def mandatory_options
+ self.class.mandatory_options
+ end
+
+ # Convenient access to class default options.
+ def default_options
+ self.class.default_options
+ end
+
+ # Merge together our instance options. In increasing precedence:
+ # default_options (class default options)
+ # options (instance options)
+ # runtime_options (provided as argument)
+ # mandatory_options (class mandatory options)
+ def full_options(runtime_options = {})
+ self.class.full_options(options.merge(runtime_options))
+ end
+
+ # Parse arguments into the options hash. Classes may customize
+ # parsing behavior by overriding these methods:
+ # #banner Usage: ./script/generate [options]
+ # #add_options! Options:
+ # some options..
+ # #add_general_options! General Options:
+ # general options..
+ def parse!(args, runtime_options = {})
+ self.options = {}
+
+ @option_parser = OptionParser.new do |opt|
+ opt.banner = banner
+ add_options!(opt)
+ add_general_options!(opt)
+ opt.parse!(args)
+ end
+
+ return args
+ ensure
+ self.options = full_options(runtime_options)
+ end
+
+ # Raise a usage error. Override usage_message to provide a blurb
+ # after the option parser summary.
+ def usage(message = usage_message)
+ raise UsageError, "#{@option_parser}\n#{message}"
+ end
+
+ def usage_message
+ ''
+ end
+
+ # Override with your own usage banner.
+ def banner
+ "Usage: #{$0} [options]"
+ end
+
+ # Override to add your options to the parser:
+ # def add_options!(opt)
+ # opt.on('-v', '--verbose') { |value| options[:verbose] = value }
+ # end
+ def add_options!(opt)
+ end
+
+ # Adds general options like -h and --quiet. Usually don't override.
+ def add_general_options!(opt)
+ opt.separator ''
+ opt.separator 'Rails Info:'
+ opt.on('-v', '--version', 'Show the Rails version number and quit.')
+ opt.on('-h', '--help', 'Show this help message and quit.') { |v| options[:help] = v }
+
+ opt.separator ''
+ opt.separator 'General Options:'
+
+ opt.on('-p', '--pretend', 'Run but do not make any changes.') { |v| options[:pretend] = v }
+ opt.on('-f', '--force', 'Overwrite files that already exist.') { options[:collision] = :force }
+ opt.on('-s', '--skip', 'Skip files that already exist.') { options[:collision] = :skip }
+ opt.on('-q', '--quiet', 'Suppress normal output.') { |v| options[:quiet] = v }
+ opt.on('-t', '--backtrace', 'Debugging: show backtrace on errors.') { |v| options[:backtrace] = v }
+ opt.on('-c', '--svn', 'Modify files with subversion. (Note: svn must be in path)') do
+ options[:svn] = `svn status`.inject({}) do |opt, e|
+ opt[e.chomp[7..-1]] = true
+ opt
+ end
+ end
+ end
+
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/scripts.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/scripts.rb
new file mode 100644
index 000000000..bd380aad6
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/scripts.rb
@@ -0,0 +1,86 @@
+require File.dirname(__FILE__) + '/options'
+
+module Rails
+ module Generator
+ module Scripts
+
+ # Generator scripts handle command-line invocation. Each script
+ # responds to an invoke! class method which handles option parsing
+ # and generator invocation.
+ class Base
+ include Options
+ default_options :collision => :ask, :quiet => false
+
+ # Run the generator script. Takes an array of unparsed arguments
+ # and a hash of parsed arguments, takes the generator as an option
+ # or first remaining argument, and invokes the requested command.
+ def run(args = [], runtime_options = {})
+ begin
+ parse!(args.dup, runtime_options)
+ rescue OptionParser::InvalidOption => e
+ # Don't cry, script. Generators want what you think is invalid.
+ end
+
+ # Generator name is the only required option.
+ unless options[:generator]
+ usage if args.empty?
+ options[:generator] ||= args.shift
+ end
+
+ # Look up generator instance and invoke command on it.
+ Rails::Generator::Base.instance(options[:generator], args, options).command(options[:command]).invoke!
+ rescue => e
+ puts e
+ puts " #{e.backtrace.join("\n ")}\n" if options[:backtrace]
+ raise SystemExit
+ end
+
+ protected
+ # Override with your own script usage banner.
+ def banner
+ "Usage: #{$0} generator [options] [args]"
+ end
+
+ def usage_message
+ usage = "\nInstalled Generators\n"
+ Rails::Generator::Base.sources.inject({}) do |mem, source|
+ label = source.label.to_s.capitalize
+ mem[label] ||= []
+ mem[label] |= source.names
+ mem
+ end.each_pair do |label, names|
+ usage << " #{label}: #{names.join(', ')}\n" unless names.empty?
+ end
+
+ usage << <<end_blurb
+
+More are available at http://rubyonrails.org/show/Generators
+ 1. Download, for example, login_generator.zip
+ 2. Unzip to directory #{Dir.user_home}/.rails/generators/login
+ to use the generator with all your Rails apps
+end_blurb
+
+ if Object.const_defined?(:RAILS_ROOT)
+ usage << <<end_blurb
+ or to #{File.expand_path(RAILS_ROOT)}/lib/generators/login
+ to use with this app only.
+end_blurb
+ end
+
+ usage << <<end_blurb
+ 3. Run generate with no arguments for usage information
+ #{$0} login
+
+Generator gems are also available:
+ 1. gem search -r generator
+ 2. gem install login_generator
+ 3. #{$0} login
+
+end_blurb
+ return usage
+ end
+ end # Base
+
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/scripts/destroy.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/scripts/destroy.rb
new file mode 100644
index 000000000..4fcbc3e0d
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/scripts/destroy.rb
@@ -0,0 +1,30 @@
+require File.dirname(__FILE__) + '/../scripts'
+
+module Rails::Generator::Scripts
+ class Destroy < Base
+ mandatory_options :command => :destroy
+
+ protected
+ def usage_message
+ usage = "\nInstalled Generators\n"
+ Rails::Generator::Base.sources.each do |source|
+ label = source.label.to_s.capitalize
+ names = source.names
+ usage << " #{label}: #{names.join(', ')}\n" unless names.empty?
+ end
+
+ usage << <<end_blurb
+
+This script will destroy all files created by the corresponding
+script/generate command. For instance, script/destroy migration CreatePost
+will delete the appropriate ###_create_post.rb file in db/migrate, while
+script/destroy scaffold Post will delete the posts controller and
+views, post model and migration, all associated tests, and the map.resources
+:posts line in config/routes.rb.
+
+For instructions on finding new generators, run script/generate
+end_blurb
+ return usage
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/scripts/generate.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/scripts/generate.rb
new file mode 100644
index 000000000..1fe2f54ab
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/scripts/generate.rb
@@ -0,0 +1,7 @@
+require File.dirname(__FILE__) + '/../scripts'
+
+module Rails::Generator::Scripts
+ class Generate < Base
+ mandatory_options :command => :create
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/scripts/update.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/scripts/update.rb
new file mode 100644
index 000000000..53a9faa36
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/scripts/update.rb
@@ -0,0 +1,12 @@
+require File.dirname(__FILE__) + '/../scripts'
+
+module Rails::Generator::Scripts
+ class Update < Base
+ mandatory_options :command => :update
+
+ protected
+ def banner
+ "Usage: #{$0} [options] scaffold"
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/secret_key_generator.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/secret_key_generator.rb
new file mode 100644
index 000000000..497df72ce
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/secret_key_generator.rb
@@ -0,0 +1,160 @@
+# A class for creating random secret keys. This class will do its best to create a
+# random secret key that's as secure as possible, using whatever methods are
+# available on the current platform. For example:
+#
+# generator = Rails::SecretKeyGenerator("some unique identifier, such as the application name")
+# generator.generate_secret # => "f3f1be90053fa851... (some long string)"
+
+module Rails
+ class SecretKeyGenerator
+ GENERATORS = [ :secure_random, :win32_api, :urandom, :openssl, :prng ].freeze
+
+ def initialize(identifier)
+ @identifier = identifier
+ end
+
+ # Generate a random secret key with the best possible method available on
+ # the current platform.
+ def generate_secret
+ generator = GENERATORS.find do |g|
+ self.class.send("supports_#{g}?")
+ end
+ send("generate_secret_with_#{generator}")
+ end
+
+ # Generate a random secret key by using the Win32 API. Raises LoadError
+ # if the current platform cannot make use of the Win32 API. Raises
+ # SystemCallError if some other error occured.
+ def generate_secret_with_win32_api
+ # Following code is based on David Garamond's GUID library for Ruby.
+ require 'Win32API'
+
+ crypt_acquire_context = Win32API.new("advapi32", "CryptAcquireContext",
+ 'PPPII', 'L')
+ crypt_gen_random = Win32API.new("advapi32", "CryptGenRandom",
+ 'LIP', 'L')
+ crypt_release_context = Win32API.new("advapi32", "CryptReleaseContext",
+ 'LI', 'L')
+ prov_rsa_full = 1
+ crypt_verifycontext = 0xF0000000
+
+ hProvStr = " " * 4
+ if crypt_acquire_context.call(hProvStr, nil, nil, prov_rsa_full,
+ crypt_verifycontext) == 0
+ raise SystemCallError, "CryptAcquireContext failed: #{lastWin32ErrorMessage}"
+ end
+ hProv, = hProvStr.unpack('L')
+ bytes = " " * 64
+ if crypt_gen_random.call(hProv, bytes.size, bytes) == 0
+ raise SystemCallError, "CryptGenRandom failed: #{lastWin32ErrorMessage}"
+ end
+ if crypt_release_context.call(hProv, 0) == 0
+ raise SystemCallError, "CryptReleaseContext failed: #{lastWin32ErrorMessage}"
+ end
+ bytes.unpack("H*")[0]
+ end
+
+ # Generate a random secret key with Ruby 1.9's SecureRandom module.
+ # Raises LoadError if the current Ruby version does not support
+ # SecureRandom.
+ def generate_secret_with_secure_random
+ require 'securerandom'
+ return SecureRandom.hex(64)
+ end
+
+ # Generate a random secret key with OpenSSL. If OpenSSL is not
+ # already loaded, then this method will attempt to load it.
+ # LoadError will be raised if that fails.
+ def generate_secret_with_openssl
+ require 'openssl'
+ if !File.exist?("/dev/urandom")
+ # OpenSSL transparently seeds the random number generator with
+ # data from /dev/urandom. On platforms where that is not
+ # available, such as Windows, we have to provide OpenSSL with
+ # our own seed. Unfortunately there's no way to provide a
+ # secure seed without OS support, so we'll have to do with
+ # rand() and Time.now.usec().
+ OpenSSL::Random.seed(rand(0).to_s + Time.now.usec.to_s)
+ end
+ data = OpenSSL::BN.rand(2048, -1, false).to_s
+ return OpenSSL::Digest::SHA512.new(data).hexdigest
+ end
+
+ # Generate a random secret key with /dev/urandom.
+ # Raises SystemCallError on failure.
+ def generate_secret_with_urandom
+ return File.read("/dev/urandom", 64).unpack("H*")[0]
+ end
+
+ # Generate a random secret key with Ruby's pseudo random number generator,
+ # as well as some environment information.
+ #
+ # This is the least cryptographically secure way to generate a secret key,
+ # and should be avoided whenever possible.
+ def generate_secret_with_prng
+ require 'digest/sha2'
+ sha = Digest::SHA2.new(512)
+ now = Time.now
+ sha << now.to_s
+ sha << String(now.usec)
+ sha << String(rand(0))
+ sha << String($$)
+ sha << @identifier
+ return sha.hexdigest
+ end
+
+ private
+ def lastWin32ErrorMessage
+ # Following code is based on David Garamond's GUID library for Ruby.
+ get_last_error = Win32API.new("kernel32", "GetLastError", '', 'L')
+ format_message = Win32API.new("kernel32", "FormatMessageA",
+ 'LPLLPLPPPPPPPP', 'L')
+ format_message_ignore_inserts = 0x00000200
+ format_message_from_system = 0x00001000
+
+ code = get_last_error.call
+ msg = "\0" * 1024
+ len = format_message.call(format_message_ignore_inserts +
+ format_message_from_system, 0,
+ code, 0, msg, 1024, nil, nil,
+ nil, nil, nil, nil, nil, nil)
+ msg[0, len].tr("\r", '').chomp
+ end
+
+ def self.supports_secure_random?
+ begin
+ require 'securerandom'
+ true
+ rescue LoadError
+ false
+ end
+ end
+
+ def self.supports_win32_api?
+ return false unless RUBY_PLATFORM =~ /(:?mswin|mingw)/
+ begin
+ require 'Win32API'
+ true
+ rescue LoadError
+ false
+ end
+ end
+
+ def self.supports_urandom?
+ File.exist?('/dev/urandom')
+ end
+
+ def self.supports_openssl?
+ begin
+ require 'openssl'
+ true
+ rescue LoadError
+ false
+ end
+ end
+
+ def self.supports_prng?
+ true
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/simple_logger.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/simple_logger.rb
new file mode 100644
index 000000000..d750f07b8
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/simple_logger.rb
@@ -0,0 +1,46 @@
+module Rails
+ module Generator
+ class SimpleLogger # :nodoc:
+ attr_reader :out
+ attr_accessor :quiet
+
+ def initialize(out = $stdout)
+ @out = out
+ @quiet = false
+ @level = 0
+ end
+
+ def log(status, message, &block)
+ @out.print("%12s %s%s\n" % [status, ' ' * @level, message]) unless quiet
+ indent(&block) if block_given?
+ end
+
+ def indent(&block)
+ @level += 1
+ if block_given?
+ begin
+ block.call
+ ensure
+ outdent
+ end
+ end
+ end
+
+ def outdent
+ @level -= 1
+ if block_given?
+ begin
+ block.call
+ ensure
+ indent
+ end
+ end
+ end
+
+ private
+ def method_missing(method, *args, &block)
+ log(method.to_s, args.first, &block)
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rails_generator/spec.rb b/vendor/rails-2.0.2/railties/lib/rails_generator/spec.rb
new file mode 100644
index 000000000..9d780b7ac
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rails_generator/spec.rb
@@ -0,0 +1,44 @@
+module Rails
+ module Generator
+ # A spec knows where a generator was found and how to instantiate it.
+ # Metadata include the generator's name, its base path, and the source
+ # which yielded it (PathSource, GemPathSource, etc.)
+ class Spec
+ attr_reader :name, :path, :source
+
+ def initialize(name, path, source)
+ @name, @path, @source = name, path, source
+ end
+
+ # Look up the generator class. Require its class file, find the class
+ # in ObjectSpace, tag it with this spec, and return.
+ def klass
+ unless @klass
+ require class_file
+ @klass = lookup_class
+ @klass.spec = self
+ end
+ @klass
+ end
+
+ def class_file
+ "#{path}/#{name}_generator.rb"
+ end
+
+ def class_name
+ "#{name.camelize}Generator"
+ end
+
+ private
+ # Search for the first Class descending from Rails::Generator::Base
+ # whose name matches the requested class name.
+ def lookup_class
+ ObjectSpace.each_object(Class) do |obj|
+ return obj if obj.ancestors.include?(Rails::Generator::Base) and
+ obj.name.split('::').last == class_name
+ end
+ raise NameError, "Missing #{class_name} class in #{class_file}"
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/railties_path.rb b/vendor/rails-2.0.2/railties/lib/railties_path.rb
new file mode 100644
index 000000000..a298a4cc2
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/railties_path.rb
@@ -0,0 +1 @@
+RAILTIES_PATH = File.join(File.dirname(__FILE__), '..')
diff --git a/vendor/rails-2.0.2/railties/lib/ruby_version_check.rb b/vendor/rails-2.0.2/railties/lib/ruby_version_check.rb
new file mode 100644
index 000000000..68d3acc87
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/ruby_version_check.rb
@@ -0,0 +1,17 @@
+min_release = "1.8.2 (2004-12-25)"
+ruby_release = "#{RUBY_VERSION} (#{RUBY_RELEASE_DATE})"
+if ruby_release =~ /1\.8\.3/
+ abort <<-end_message
+
+ Rails does not work with Ruby version 1.8.3.
+ Please upgrade to version 1.8.4 or downgrade to 1.8.2.
+
+ end_message
+elsif ruby_release < min_release
+ abort <<-end_message
+
+ Rails requires Ruby version #{min_release} or later.
+ You're running #{ruby_release}; please upgrade to continue.
+
+ end_message
+end
diff --git a/vendor/rails-2.0.2/railties/lib/rubyprof_ext.rb b/vendor/rails-2.0.2/railties/lib/rubyprof_ext.rb
new file mode 100644
index 000000000..f6e90357c
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/rubyprof_ext.rb
@@ -0,0 +1,35 @@
+require 'prof'
+
+module Prof #:nodoc:
+ # Adapted from Shugo Maeda's unprof.rb
+ def self.print_profile(results, io = $stderr)
+ total = results.detect { |i|
+ i.method_class.nil? && i.method_id == :"#toplevel"
+ }.total_time
+ total = 0.001 if total < 0.001
+
+ io.puts " %% cumulative self self total"
+ io.puts " time seconds seconds calls ms/call ms/call name"
+
+ sum = 0.0
+ for r in results
+ sum += r.self_time
+
+ name = if r.method_class.nil?
+ r.method_id.to_s
+ elsif r.method_class.is_a?(Class)
+ "#{r.method_class}##{r.method_id}"
+ else
+ "#{r.method_class}.#{r.method_id}"
+ end
+ io.printf "%6.2f %8.3f %8.3f %8d %8.2f %8.2f %s\n",
+ r.self_time / total * 100,
+ sum,
+ r.self_time,
+ r.count,
+ r.self_time * 1000 / r.count,
+ r.total_time * 1000 / r.count,
+ name
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/source_annotation_extractor.rb b/vendor/rails-2.0.2/railties/lib/source_annotation_extractor.rb
new file mode 100644
index 000000000..884422653
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/source_annotation_extractor.rb
@@ -0,0 +1,62 @@
+class SourceAnnotationExtractor
+ class Annotation < Struct.new(:line, :tag, :text)
+ def to_s(options={})
+ s = "[%3d] " % line
+ s << "[#{tag}] " if options[:tag]
+ s << text
+ end
+ end
+
+ def self.enumerate(tag, options={})
+ extractor = new(tag)
+ extractor.display(extractor.find, options)
+ end
+
+ attr_reader :tag
+
+ def initialize(tag)
+ @tag = tag
+ end
+
+ def find(dirs=%w(app lib test))
+ dirs.inject({}) { |h, dir| h.update(find_in(dir)) }
+ end
+
+ def find_in(dir)
+ results = {}
+
+ Dir.glob("#{dir}/*") do |item|
+ next if File.basename(item)[0] == ?.
+
+ if File.directory?(item)
+ results.update(find_in(item))
+ elsif item =~ /\.(builder|(r(?:b|xml|js)))$/
+ results.update(extract_annotations_from(item, /#\s*(#{tag}):?\s*(.*)$/))
+ elsif item =~ /\.(rhtml|erb)$/
+ results.update(extract_annotations_from(item, /<%\s*#\s*(#{tag}):?\s*(.*?)\s*%>/))
+ end
+ end
+
+ results
+ end
+
+ def extract_annotations_from(file, pattern)
+ lineno = 0
+ result = File.readlines(file).inject([]) do |list, line|
+ lineno += 1
+ next list unless line =~ pattern
+ list << Annotation.new(lineno, $1, $2)
+ end
+ result.empty? ? {} : { file => result }
+ end
+
+ def display(results, options={})
+ results.keys.sort.each do |file|
+ puts "#{file}:"
+ results[file].each do |note|
+ puts " * #{note.to_s(options)}"
+ end
+ puts
+ end
+ end
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/railties/lib/tasks/annotations.rake b/vendor/rails-2.0.2/railties/lib/tasks/annotations.rake
new file mode 100644
index 000000000..ea6046670
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/tasks/annotations.rake
@@ -0,0 +1,23 @@
+require 'source_annotation_extractor'
+
+desc "Enumerate all annotations"
+task :notes do
+ SourceAnnotationExtractor.enumerate "OPTIMIZE|FIXME|TODO", :tag => true
+end
+
+namespace :notes do
+ desc "Enumerate all OPTIMIZE annotations"
+ task :optimize do
+ SourceAnnotationExtractor.enumerate "OPTIMIZE"
+ end
+
+ desc "Enumerate all FIXME annotations"
+ task :fixme do
+ SourceAnnotationExtractor.enumerate "FIXME"
+ end
+
+ desc "Enumerate all TODO annotations"
+ task :todo do
+ SourceAnnotationExtractor.enumerate "TODO"
+ end
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/railties/lib/tasks/databases.rake b/vendor/rails-2.0.2/railties/lib/tasks/databases.rake
new file mode 100644
index 000000000..2ecd09af2
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/tasks/databases.rake
@@ -0,0 +1,363 @@
+namespace :db do
+ namespace :create do
+ desc 'Create all the local databases defined in config/database.yml'
+ task :all => :environment do
+ ActiveRecord::Base.configurations.each_value do |config|
+ # Skip entries that don't have a database key, such as the first entry here:
+ #
+ # defaults: &defaults
+ # adapter: mysql
+ # username: root
+ # password:
+ # host: localhost
+ #
+ # development:
+ # database: blog_development
+ # <<: *defaults
+ next unless config['database']
+ # Only connect to local databases
+ if %w( 127.0.0.1 localhost ).include?(config['host']) || config['host'].blank?
+ create_database(config)
+ else
+ p "This task only creates local databases. #{config['database']} is on a remote host."
+ end
+ end
+ end
+ end
+
+ desc 'Create the database defined in config/database.yml for the current RAILS_ENV'
+ task :create => :environment do
+ create_database(ActiveRecord::Base.configurations[RAILS_ENV])
+ end
+
+ def create_database(config)
+ begin
+ ActiveRecord::Base.establish_connection(config)
+ ActiveRecord::Base.connection
+ rescue
+ case config['adapter']
+ when 'mysql'
+ @charset = ENV['CHARSET'] || 'utf8'
+ @collation = ENV['COLLATION'] || 'utf8_general_ci'
+ begin
+ ActiveRecord::Base.establish_connection(config.merge({'database' => nil}))
+ ActiveRecord::Base.connection.create_database(config['database'], {:charset => @charset, :collation => @collation})
+ ActiveRecord::Base.establish_connection(config)
+ rescue
+ $stderr.puts "Couldn't create database for #{config.inspect}"
+ end
+ when 'postgresql'
+ `createdb "#{config['database']}" -E utf8`
+ when 'sqlite'
+ `sqlite "#{config['database']}"`
+ when 'sqlite3'
+ `sqlite3 "#{config['database']}"`
+ end
+ else
+ p "#{config['database']} already exists"
+ end
+ end
+
+ namespace :drop do
+ desc 'Drops all the local databases defined in config/database.yml'
+ task :all => :environment do
+ ActiveRecord::Base.configurations.each_value do |config|
+ # Skip entries that don't have a database key
+ next unless config['database']
+ # Only connect to local databases
+ if config['host'] == 'localhost' || config['host'].blank?
+ drop_database(config)
+ else
+ p "This task only drops local databases. #{config['database']} is on a remote host."
+ end
+ end
+ end
+ end
+
+ desc 'Drops the database for the current RAILS_ENV'
+ task :drop => :environment do
+ drop_database(ActiveRecord::Base.configurations[RAILS_ENV || 'development'])
+ end
+
+ desc "Migrate the database through scripts in db/migrate. Target specific version with VERSION=x. Turn off output with VERBOSE=false."
+ task :migrate => :environment do
+ ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
+ ActiveRecord::Migrator.migrate("db/migrate/", ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
+ Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
+ end
+
+ namespace :migrate do
+ desc 'Rollbacks the database one migration and re migrate up. If you want to rollback more than one step, define STEP=x'
+ task :redo => [ 'db:rollback', 'db:migrate' ]
+
+ desc 'Resets your database using your migrations for the current environment'
+ task :reset => ["db:drop", "db:create", "db:migrate"]
+ end
+
+ desc 'Rolls the schema back to the previous version. Specify the number of steps with STEP=n'
+ task :rollback => :environment do
+ step = ENV['STEP'] ? ENV['STEP'].to_i : 1
+ version = ActiveRecord::Migrator.current_version - step
+ ActiveRecord::Migrator.migrate('db/migrate/', version)
+ end
+
+ desc 'Drops and recreates the database from db/schema.rb for the current environment.'
+ task :reset => ['db:drop', 'db:create', 'db:schema:load']
+
+ desc "Retrieves the charset for the current environment's database"
+ task :charset => :environment do
+ config = ActiveRecord::Base.configurations[RAILS_ENV || 'development']
+ case config['adapter']
+ when 'mysql'
+ ActiveRecord::Base.establish_connection(config)
+ puts ActiveRecord::Base.connection.charset
+ else
+ puts 'sorry, your database adapter is not supported yet, feel free to submit a patch'
+ end
+ end
+
+ desc "Retrieves the collation for the current environment's database"
+ task :collation => :environment do
+ config = ActiveRecord::Base.configurations[RAILS_ENV || 'development']
+ case config['adapter']
+ when 'mysql'
+ ActiveRecord::Base.establish_connection(config)
+ puts ActiveRecord::Base.connection.collation
+ else
+ puts 'sorry, your database adapter is not supported yet, feel free to submit a patch'
+ end
+ end
+
+ desc "Retrieves the current schema version number"
+ task :version => :environment do
+ puts "Current version: #{ActiveRecord::Migrator.current_version}"
+ end
+
+ desc "Raises an error if there are pending migrations"
+ task :abort_if_pending_migrations => :environment do
+ if defined? ActiveRecord
+ pending_migrations = ActiveRecord::Migrator.new(:up, 'db/migrate').pending_migrations
+
+ if pending_migrations.any?
+ puts "You have #{pending_migrations.size} pending migrations:"
+ pending_migrations.each do |pending_migration|
+ puts ' %4d %s' % [pending_migration.version, pending_migration.name]
+ end
+ abort "Run `rake db:migrate` to update your database then try again."
+ end
+ end
+ end
+
+ namespace :fixtures do
+ desc "Load fixtures into the current environment's database. Load specific fixtures using FIXTURES=x,y"
+ task :load => :environment do
+ require 'active_record/fixtures'
+ ActiveRecord::Base.establish_connection(RAILS_ENV.to_sym)
+ (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : Dir.glob(File.join(RAILS_ROOT, 'test', 'fixtures', '*.{yml,csv}'))).each do |fixture_file|
+ Fixtures.create_fixtures('test/fixtures', File.basename(fixture_file, '.*'))
+ end
+ end
+
+ desc "Search for a fixture given a LABEL or ID."
+ task :identify => :environment do
+ require "active_record/fixtures"
+
+ label, id = ENV["LABEL"], ENV["ID"]
+ raise "LABEL or ID required" if label.blank? && id.blank?
+
+ puts %Q(The fixture ID for "#{label}" is #{Fixtures.identify(label)}.) if label
+
+ Dir["#{RAILS_ROOT}/test/fixtures/**/*.yml"].each do |file|
+ if data = YAML::load(ERB.new(IO.read(file)).result)
+ data.keys.each do |key|
+ key_id = Fixtures.identify(key)
+
+ if key == label || key_id == id.to_i
+ puts "#{file}: #{key} (#{key_id})"
+ end
+ end
+ end
+ end
+ end
+ end
+
+ namespace :schema do
+ desc "Create a db/schema.rb file that can be portably used against any DB supported by AR"
+ task :dump => :environment do
+ require 'active_record/schema_dumper'
+ File.open(ENV['SCHEMA'] || "db/schema.rb", "w") do |file|
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
+ end
+ end
+
+ desc "Load a schema.rb file into the database"
+ task :load => :environment do
+ file = ENV['SCHEMA'] || "db/schema.rb"
+ load(file)
+ end
+ end
+
+ namespace :structure do
+ desc "Dump the database structure to a SQL file"
+ task :dump => :environment do
+ abcs = ActiveRecord::Base.configurations
+ case abcs[RAILS_ENV]["adapter"]
+ when "mysql", "oci", "oracle"
+ ActiveRecord::Base.establish_connection(abcs[RAILS_ENV])
+ File.open("db/#{RAILS_ENV}_structure.sql", "w+") { |f| f << ActiveRecord::Base.connection.structure_dump }
+ when "postgresql"
+ ENV['PGHOST'] = abcs[RAILS_ENV]["host"] if abcs[RAILS_ENV]["host"]
+ ENV['PGPORT'] = abcs[RAILS_ENV]["port"].to_s if abcs[RAILS_ENV]["port"]
+ ENV['PGPASSWORD'] = abcs[RAILS_ENV]["password"].to_s if abcs[RAILS_ENV]["password"]
+ search_path = abcs[RAILS_ENV]["schema_search_path"]
+ search_path = "--schema=#{search_path}" if search_path
+ `pg_dump -i -U "#{abcs[RAILS_ENV]["username"]}" -s -x -O -f db/#{RAILS_ENV}_structure.sql #{search_path} #{abcs[RAILS_ENV]["database"]}`
+ raise "Error dumping database" if $?.exitstatus == 1
+ when "sqlite", "sqlite3"
+ dbfile = abcs[RAILS_ENV]["database"] || abcs[RAILS_ENV]["dbfile"]
+ `#{abcs[RAILS_ENV]["adapter"]} #{dbfile} .schema > db/#{RAILS_ENV}_structure.sql`
+ when "sqlserver"
+ `scptxfr /s #{abcs[RAILS_ENV]["host"]} /d #{abcs[RAILS_ENV]["database"]} /I /f db\\#{RAILS_ENV}_structure.sql /q /A /r`
+ `scptxfr /s #{abcs[RAILS_ENV]["host"]} /d #{abcs[RAILS_ENV]["database"]} /I /F db\ /q /A /r`
+ when "firebird"
+ set_firebird_env(abcs[RAILS_ENV])
+ db_string = firebird_db_string(abcs[RAILS_ENV])
+ sh "isql -a #{db_string} > db/#{RAILS_ENV}_structure.sql"
+ else
+ raise "Task not supported by '#{abcs["test"]["adapter"]}'"
+ end
+
+ if ActiveRecord::Base.connection.supports_migrations?
+ File.open("db/#{RAILS_ENV}_structure.sql", "a") { |f| f << ActiveRecord::Base.connection.dump_schema_information }
+ end
+ end
+ end
+
+ namespace :test do
+ desc "Recreate the test database from the current environment's database schema"
+ task :clone => %w(db:schema:dump db:test:purge) do
+ ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test'])
+ ActiveRecord::Schema.verbose = false
+ Rake::Task["db:schema:load"].invoke
+ end
+
+
+ desc "Recreate the test databases from the development structure"
+ task :clone_structure => [ "db:structure:dump", "db:test:purge" ] do
+ abcs = ActiveRecord::Base.configurations
+ case abcs["test"]["adapter"]
+ when "mysql"
+ ActiveRecord::Base.establish_connection(:test)
+ ActiveRecord::Base.connection.execute('SET foreign_key_checks = 0')
+ IO.readlines("db/#{RAILS_ENV}_structure.sql").join.split("\n\n").each do |table|
+ ActiveRecord::Base.connection.execute(table)
+ end
+ when "postgresql"
+ ENV['PGHOST'] = abcs["test"]["host"] if abcs["test"]["host"]
+ ENV['PGPORT'] = abcs["test"]["port"].to_s if abcs["test"]["port"]
+ ENV['PGPASSWORD'] = abcs["test"]["password"].to_s if abcs["test"]["password"]
+ `psql -U "#{abcs["test"]["username"]}" -f db/#{RAILS_ENV}_structure.sql #{abcs["test"]["database"]}`
+ when "sqlite", "sqlite3"
+ dbfile = abcs["test"]["database"] || abcs["test"]["dbfile"]
+ `#{abcs["test"]["adapter"]} #{dbfile} < db/#{RAILS_ENV}_structure.sql`
+ when "sqlserver"
+ `osql -E -S #{abcs["test"]["host"]} -d #{abcs["test"]["database"]} -i db\\#{RAILS_ENV}_structure.sql`
+ when "oci", "oracle"
+ ActiveRecord::Base.establish_connection(:test)
+ IO.readlines("db/#{RAILS_ENV}_structure.sql").join.split(";\n\n").each do |ddl|
+ ActiveRecord::Base.connection.execute(ddl)
+ end
+ when "firebird"
+ set_firebird_env(abcs["test"])
+ db_string = firebird_db_string(abcs["test"])
+ sh "isql -i db/#{RAILS_ENV}_structure.sql #{db_string}"
+ else
+ raise "Task not supported by '#{abcs["test"]["adapter"]}'"
+ end
+ end
+
+ desc "Empty the test database"
+ task :purge => :environment do
+ abcs = ActiveRecord::Base.configurations
+ case abcs["test"]["adapter"]
+ when "mysql"
+ ActiveRecord::Base.establish_connection(:test)
+ ActiveRecord::Base.connection.recreate_database(abcs["test"]["database"])
+ when "postgresql"
+ ENV['PGHOST'] = abcs["test"]["host"] if abcs["test"]["host"]
+ ENV['PGPORT'] = abcs["test"]["port"].to_s if abcs["test"]["port"]
+ ENV['PGPASSWORD'] = abcs["test"]["password"].to_s if abcs["test"]["password"]
+ enc_option = "-E #{abcs["test"]["encoding"]}" if abcs["test"]["encoding"]
+
+ ActiveRecord::Base.clear_active_connections!
+ `dropdb -U "#{abcs["test"]["username"]}" #{abcs["test"]["database"]}`
+ `createdb #{enc_option} -U "#{abcs["test"]["username"]}" #{abcs["test"]["database"]}`
+ when "sqlite","sqlite3"
+ dbfile = abcs["test"]["database"] || abcs["test"]["dbfile"]
+ File.delete(dbfile) if File.exist?(dbfile)
+ when "sqlserver"
+ dropfkscript = "#{abcs["test"]["host"]}.#{abcs["test"]["database"]}.DP1".gsub(/\\/,'-')
+ `osql -E -S #{abcs["test"]["host"]} -d #{abcs["test"]["database"]} -i db\\#{dropfkscript}`
+ `osql -E -S #{abcs["test"]["host"]} -d #{abcs["test"]["database"]} -i db\\#{RAILS_ENV}_structure.sql`
+ when "oci", "oracle"
+ ActiveRecord::Base.establish_connection(:test)
+ ActiveRecord::Base.connection.structure_drop.split(";\n\n").each do |ddl|
+ ActiveRecord::Base.connection.execute(ddl)
+ end
+ when "firebird"
+ ActiveRecord::Base.establish_connection(:test)
+ ActiveRecord::Base.connection.recreate_database!
+ else
+ raise "Task not supported by '#{abcs["test"]["adapter"]}'"
+ end
+ end
+
+ desc 'Prepare the test database and load the schema'
+ task :prepare => %w(environment db:abort_if_pending_migrations) do
+ if defined?(ActiveRecord) && !ActiveRecord::Base.configurations.blank?
+ Rake::Task[{ :sql => "db:test:clone_structure", :ruby => "db:test:clone" }[ActiveRecord::Base.schema_format]].invoke
+ end
+ end
+ end
+
+ namespace :sessions do
+ desc "Creates a sessions migration for use with CGI::Session::ActiveRecordStore"
+ task :create => :environment do
+ raise "Task unavailable to this database (no migration support)" unless ActiveRecord::Base.connection.supports_migrations?
+ require 'rails_generator'
+ require 'rails_generator/scripts/generate'
+ Rails::Generator::Scripts::Generate.new.run(["session_migration", ENV["MIGRATION"] || "CreateSessions"])
+ end
+
+ desc "Clear the sessions table"
+ task :clear => :environment do
+ session_table = 'session'
+ session_table = Inflector.pluralize(session_table) if ActiveRecord::Base.pluralize_table_names
+ ActiveRecord::Base.connection.execute "DELETE FROM #{session_table}"
+ end
+ end
+end
+
+def drop_database(config)
+ case config['adapter']
+ when 'mysql'
+ ActiveRecord::Base.connection.drop_database config['database']
+ when /^sqlite/
+ FileUtils.rm_f(File.join(RAILS_ROOT, config['database']))
+ when 'postgresql'
+ `dropdb "#{config['database']}"`
+ end
+end
+
+def session_table_name
+ ActiveRecord::Base.pluralize_table_names ? :sessions : :session
+end
+
+def set_firebird_env(config)
+ ENV["ISC_USER"] = config["username"].to_s if config["username"]
+ ENV["ISC_PASSWORD"] = config["password"].to_s if config["password"]
+end
+
+def firebird_db_string(config)
+ FireRuby::Database.db_string_for(config.symbolize_keys)
+end
diff --git a/vendor/rails-2.0.2/railties/lib/tasks/documentation.rake b/vendor/rails-2.0.2/railties/lib/tasks/documentation.rake
new file mode 100644
index 000000000..41e52f137
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/tasks/documentation.rake
@@ -0,0 +1,80 @@
+namespace :doc do
+ desc "Generate documentation for the application. Set custom template with TEMPLATE=/path/to/rdoc/template.rb"
+ Rake::RDocTask.new("app") { |rdoc|
+ rdoc.rdoc_dir = 'doc/app'
+ rdoc.template = ENV['template'] if ENV['template']
+ rdoc.title = "Rails Application Documentation"
+ rdoc.options << '--line-numbers' << '--inline-source'
+ rdoc.options << '--charset' << 'utf-8'
+ rdoc.rdoc_files.include('doc/README_FOR_APP')
+ rdoc.rdoc_files.include('app/**/*.rb')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+ }
+
+ desc "Generate documentation for the Rails framework"
+ Rake::RDocTask.new("rails") { |rdoc|
+ rdoc.rdoc_dir = 'doc/api'
+ rdoc.template = "#{ENV['template']}.rb" if ENV['template']
+ rdoc.title = "Rails Framework Documentation"
+ rdoc.options << '--line-numbers' << '--inline-source'
+ rdoc.rdoc_files.include('README')
+ rdoc.rdoc_files.include('vendor/rails/railties/CHANGELOG')
+ rdoc.rdoc_files.include('vendor/rails/railties/MIT-LICENSE')
+ rdoc.rdoc_files.include('vendor/rails/railties/README')
+ rdoc.rdoc_files.include('vendor/rails/railties/lib/{*.rb,commands/*.rb,rails_generator/*.rb}')
+ rdoc.rdoc_files.include('vendor/rails/activerecord/README')
+ rdoc.rdoc_files.include('vendor/rails/activerecord/CHANGELOG')
+ rdoc.rdoc_files.include('vendor/rails/activerecord/lib/active_record/**/*.rb')
+ rdoc.rdoc_files.exclude('vendor/rails/activerecord/lib/active_record/vendor/*')
+ rdoc.rdoc_files.include('vendor/rails/activeresource/README')
+ rdoc.rdoc_files.include('vendor/rails/activeresource/CHANGELOG')
+ rdoc.rdoc_files.include('vendor/rails/activeresource/lib/active_resource.rb')
+ rdoc.rdoc_files.include('vendor/rails/activeresource/lib/active_resource/*')
+ rdoc.rdoc_files.include('vendor/rails/actionpack/README')
+ rdoc.rdoc_files.include('vendor/rails/actionpack/CHANGELOG')
+ rdoc.rdoc_files.include('vendor/rails/actionpack/lib/action_controller/**/*.rb')
+ rdoc.rdoc_files.include('vendor/rails/actionpack/lib/action_view/**/*.rb')
+ rdoc.rdoc_files.include('vendor/rails/actionmailer/README')
+ rdoc.rdoc_files.include('vendor/rails/actionmailer/CHANGELOG')
+ rdoc.rdoc_files.include('vendor/rails/actionmailer/lib/action_mailer/base.rb')
+ rdoc.rdoc_files.include('vendor/rails/activesupport/README')
+ rdoc.rdoc_files.include('vendor/rails/activesupport/CHANGELOG')
+ rdoc.rdoc_files.include('vendor/rails/activesupport/lib/active_support/**/*.rb')
+ }
+
+ plugins = FileList['vendor/plugins/**'].collect { |plugin| File.basename(plugin) }
+
+ desc "Generate documentation for all installed plugins"
+ task :plugins => plugins.collect { |plugin| "doc:plugins:#{plugin}" }
+
+ desc "Remove plugin documentation"
+ task :clobber_plugins do
+ rm_rf 'doc/plugins' rescue nil
+ end
+
+ namespace :plugins do
+ # Define doc tasks for each plugin
+ plugins.each do |plugin|
+ task(plugin => :environment) do
+ plugin_base = "vendor/plugins/#{plugin}"
+ options = []
+ files = Rake::FileList.new
+ options << "-o doc/plugins/#{plugin}"
+ options << "--title '#{plugin.titlecase} Plugin Documentation'"
+ options << '--line-numbers' << '--inline-source'
+ options << '-T html'
+
+ files.include("#{plugin_base}/lib/**/*.rb")
+ if File.exists?("#{plugin_base}/README")
+ files.include("#{plugin_base}/README")
+ options << "--main '#{plugin_base}/README'"
+ end
+ files.include("#{plugin_base}/CHANGELOG") if File.exists?("#{plugin_base}/CHANGELOG")
+
+ options << files.to_s
+
+ sh %(rdoc #{options * ' '})
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/tasks/framework.rake b/vendor/rails-2.0.2/railties/lib/tasks/framework.rake
new file mode 100644
index 000000000..ebc24f46a
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/tasks/framework.rake
@@ -0,0 +1,118 @@
+namespace :rails do
+ namespace :freeze do
+ desc "Lock this application to the current gems (by unpacking them into vendor/rails)"
+ task :gems do
+ deps = %w(actionpack activerecord actionmailer activesupport activeresource)
+ require 'rubygems'
+ require 'rubygems/gem_runner'
+ Gem.manage_gems
+
+ rails = (version = ENV['VERSION']) ?
+ Gem.cache.find_name('rails', "= #{version}").first :
+ Gem.cache.find_name('rails').sort_by { |g| g.version }.last
+
+ version ||= rails.version
+
+ unless rails
+ puts "No rails gem #{version} is installed. Do 'gem list rails' to see what you have available."
+ exit
+ end
+
+ puts "Freezing to the gems for Rails #{rails.version}"
+ rm_rf "vendor/rails"
+ mkdir_p "vendor/rails"
+
+ begin
+ chdir("vendor/rails") do
+ rails.dependencies.select { |g| deps.include? g.name }.each do |g|
+ Gem::GemRunner.new.run(["unpack", g.name, "--version", g.version_requirements.to_s])
+ mv(Dir.glob("#{g.name}*").first, g.name)
+ end
+
+ Gem::GemRunner.new.run(["unpack", "rails", "--version", "=#{version}"])
+ FileUtils.mv(Dir.glob("rails*").first, "railties")
+ end
+ rescue Exception
+ rm_rf "vendor/rails"
+ raise
+ end
+ end
+
+ desc "Lock to latest Edge Rails or a specific revision with REVISION=X (ex: REVISION=4021) or a tag with TAG=Y (ex: TAG=rel_1-1-0)"
+ task :edge do
+ $verbose = false
+ `svn --version` rescue nil
+ unless !$?.nil? && $?.success?
+ $stderr.puts "ERROR: Must have subversion (svn) available in the PATH to lock this application to Edge Rails"
+ exit 1
+ end
+
+ rm_rf "vendor/rails"
+ mkdir_p "vendor/rails"
+
+ svn_root = "http://dev.rubyonrails.org/svn/rails/"
+
+ if ENV['TAG']
+ rails_svn = "#{svn_root}/tags/#{ENV['TAG']}"
+ touch "vendor/rails/TAG_#{ENV['TAG']}"
+ else
+ rails_svn = "#{svn_root}/trunk"
+
+ if ENV['REVISION'].nil?
+ ENV['REVISION'] = /^r(\d+)/.match(%x{svn -qr HEAD log #{svn_root}})[1]
+ puts "REVISION not set. Using HEAD, which is revision #{ENV['REVISION']}."
+ end
+
+ touch "vendor/rails/REVISION_#{ENV['REVISION']}"
+ end
+
+ for framework in %w(railties actionpack activerecord actionmailer activesupport activeresource)
+ system "svn export #{rails_svn}/#{framework} vendor/rails/#{framework}" + (ENV['REVISION'] ? " -r #{ENV['REVISION']}" : "")
+ end
+ end
+ end
+
+ desc "Unlock this application from freeze of gems or edge and return to a fluid use of system gems"
+ task :unfreeze do
+ rm_rf "vendor/rails"
+ end
+
+ desc "Update both configs, scripts and public/javascripts from Rails"
+ task :update => [ "update:scripts", "update:javascripts", "update:configs" ]
+
+ namespace :update do
+ desc "Add new scripts to the application script/ directory"
+ task :scripts do
+ local_base = "script"
+ edge_base = "#{File.dirname(__FILE__)}/../../bin"
+
+ local = Dir["#{local_base}/**/*"].reject { |path| File.directory?(path) }
+ edge = Dir["#{edge_base}/**/*"].reject { |path| File.directory?(path) }
+
+ edge.each do |script|
+ base_name = script[(edge_base.length+1)..-1]
+ next if base_name == "rails"
+ next if local.detect { |path| base_name == path[(local_base.length+1)..-1] }
+ if !File.directory?("#{local_base}/#{File.dirname(base_name)}")
+ mkdir_p "#{local_base}/#{File.dirname(base_name)}"
+ end
+ install script, "#{local_base}/#{base_name}", :mode => 0755
+ end
+ end
+
+ desc "Update your javascripts from your current rails install"
+ task :javascripts do
+ require 'railties_path'
+ project_dir = RAILS_ROOT + '/public/javascripts/'
+ scripts = Dir[RAILTIES_PATH + '/html/javascripts/*.js']
+ scripts.reject!{|s| File.basename(s) == 'application.js'} if File.exists?(project_dir + 'application.js')
+ FileUtils.cp(scripts, project_dir)
+ end
+
+ desc "Update config/boot.rb from your current rails install"
+ task :configs do
+ require 'railties_path'
+ FileUtils.cp(RAILTIES_PATH + '/environments/boot.rb', RAILS_ROOT + '/config/boot.rb')
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/tasks/log.rake b/vendor/rails-2.0.2/railties/lib/tasks/log.rake
new file mode 100644
index 000000000..6e1334692
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/tasks/log.rake
@@ -0,0 +1,9 @@
+namespace :log do
+ desc "Truncates all *.log files in log/ to zero bytes"
+ task :clear do
+ FileList["log/*.log"].each do |log_file|
+ f = File.open(log_file, "w")
+ f.close
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/lib/tasks/misc.rake b/vendor/rails-2.0.2/railties/lib/tasks/misc.rake
new file mode 100644
index 000000000..e44ab2cf1
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/tasks/misc.rake
@@ -0,0 +1,10 @@
+task :default => :test
+task :environment do
+ require(File.join(RAILS_ROOT, 'config', 'environment'))
+end
+
+require 'rails_generator/secret_key_generator'
+desc 'Generate a crytographically secure secret key. This is typically used to generate a secret for cookie sessions. Pass a unique identifier to the generator using ID="some unique identifier" for greater security.'
+task :secret do
+ puts Rails::SecretKeyGenerator.new(ENV['ID']).generate_secret
+end
diff --git a/vendor/rails-2.0.2/railties/lib/tasks/rails.rb b/vendor/rails-2.0.2/railties/lib/tasks/rails.rb
new file mode 100644
index 000000000..bfcf5bc49
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/tasks/rails.rb
@@ -0,0 +1,8 @@
+$VERBOSE = nil
+
+# Load Rails rakefile extensions
+Dir["#{File.dirname(__FILE__)}/*.rake"].each { |ext| load ext }
+
+# Load any custom rakefile extensions
+Dir["#{RAILS_ROOT}/lib/tasks/**/*.rake"].sort.each { |ext| load ext }
+Dir["#{RAILS_ROOT}/vendor/plugins/*/**/tasks/**/*.rake"].sort.each { |ext| load ext }
diff --git a/vendor/rails-2.0.2/railties/lib/tasks/routes.rake b/vendor/rails-2.0.2/railties/lib/tasks/routes.rake
new file mode 100644
index 000000000..39b713916
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/tasks/routes.rake
@@ -0,0 +1,17 @@
+desc 'Print out all defined routes in match order, with names.'
+task :routes => :environment do
+ routes = ActionController::Routing::Routes.routes.collect do |route|
+ name = ActionController::Routing::Routes.named_routes.routes.index(route).to_s
+ verb = route.conditions[:method].to_s.upcase
+ segs = route.segments.inject("") { |str,s| str << s.to_s }
+ segs.chop! if segs.length > 1
+ reqs = route.requirements.empty? ? "" : route.requirements.inspect
+ {:name => name, :verb => verb, :segs => segs, :reqs => reqs}
+ end
+ name_width = routes.collect {|r| r[:name]}.collect {|n| n.length}.max
+ verb_width = routes.collect {|r| r[:verb]}.collect {|v| v.length}.max
+ segs_width = routes.collect {|r| r[:segs]}.collect {|s| s.length}.max
+ routes.each do |r|
+ puts "#{r[:name].rjust(name_width)} #{r[:verb].ljust(verb_width)} #{r[:segs].ljust(segs_width)} #{r[:reqs]}"
+ end
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/railties/lib/tasks/statistics.rake b/vendor/rails-2.0.2/railties/lib/tasks/statistics.rake
new file mode 100644
index 000000000..dbd077319
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/tasks/statistics.rake
@@ -0,0 +1,18 @@
+STATS_DIRECTORIES = [
+ %w(Controllers app/controllers),
+ %w(Helpers app/helpers),
+ %w(Models app/models),
+ %w(Libraries lib/),
+ %w(APIs app/apis),
+ %w(Components components),
+ %w(Integration\ tests test/integration),
+ %w(Functional\ tests test/functional),
+ %w(Unit\ tests test/unit)
+
+].collect { |name, dir| [ name, "#{RAILS_ROOT}/#{dir}" ] }.select { |name, dir| File.directory?(dir) }
+
+desc "Report code statistics (KLOCs, etc) from the application"
+task :stats do
+ require 'code_statistics'
+ CodeStatistics.new(*STATS_DIRECTORIES).to_s
+end
diff --git a/vendor/rails-2.0.2/railties/lib/tasks/testing.rake b/vendor/rails-2.0.2/railties/lib/tasks/testing.rake
new file mode 100644
index 000000000..f495031b7
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/tasks/testing.rake
@@ -0,0 +1,118 @@
+TEST_CHANGES_SINCE = Time.now - 600
+
+# Look up tests for recently modified sources.
+def recent_tests(source_pattern, test_path, touched_since = 10.minutes.ago)
+ FileList[source_pattern].map do |path|
+ if File.mtime(path) > touched_since
+ tests = []
+ source_dir = File.dirname(path).split("/")
+ source_file = File.basename(path, '.rb')
+
+ # Support subdirs in app/models and app/controllers
+ modified_test_path = source_dir.length > 2 ? "#{test_path}/" << source_dir[1..source_dir.length].join('/') : test_path
+
+ # For modified files in app/ run the tests for it. ex. /test/functional/account_controller.rb
+ test = "#{modified_test_path}/#{source_file}_test.rb"
+ tests.push test if File.exists?(test)
+
+ # For modified files in app, run tests in subdirs too. ex. /test/functional/account/*_test.rb
+ test = "#{modified_test_path}/#{File.basename(path, '.rb').sub("_controller","")}"
+ FileList["#{test}/*_test.rb"].each { |f| tests.push f } if File.exists?(test)
+
+ return tests
+
+ end
+ end.flatten.compact
+end
+
+
+# Recreated here from ActiveSupport because :uncommitted needs it before Rails is available
+module Kernel
+ def silence_stderr
+ old_stderr = STDERR.dup
+ STDERR.reopen(RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'NUL:' : '/dev/null')
+ STDERR.sync = true
+ yield
+ ensure
+ STDERR.reopen(old_stderr)
+ end
+end
+
+desc 'Test all units and functionals'
+task :test do
+ errors = %w(test:units test:functionals test:integration).collect do |task|
+ begin
+ Rake::Task[task].invoke
+ nil
+ rescue => e
+ task
+ end
+ end.compact
+ abort "Errors running #{errors.to_sentence}!" if errors.any?
+end
+
+namespace :test do
+ Rake::TestTask.new(:recent => "db:test:prepare") do |t|
+ since = TEST_CHANGES_SINCE
+ touched = FileList['test/**/*_test.rb'].select { |path| File.mtime(path) > since } +
+ recent_tests('app/models/**/*.rb', 'test/unit', since) +
+ recent_tests('app/controllers/**/*.rb', 'test/functional', since)
+
+ t.libs << 'test'
+ t.verbose = true
+ t.test_files = touched.uniq
+ end
+ Rake::Task['test:recent'].comment = "Test recent changes"
+
+ Rake::TestTask.new(:uncommitted => "db:test:prepare") do |t|
+ def t.file_list
+ changed_since_checkin = silence_stderr { `svn status` }.map { |path| path.chomp[7 .. -1] }
+
+ models = changed_since_checkin.select { |path| path =~ /app[\\\/]models[\\\/].*\.rb/ }
+ controllers = changed_since_checkin.select { |path| path =~ /app[\\\/]controllers[\\\/].*\.rb/ }
+
+ unit_tests = models.map { |model| "test/unit/#{File.basename(model, '.rb')}_test.rb" }
+ functional_tests = controllers.map { |controller| "test/functional/#{File.basename(controller, '.rb')}_test.rb" }
+
+ unit_tests.uniq + functional_tests.uniq
+ end
+
+ t.libs << 'test'
+ t.verbose = true
+ end
+ Rake::Task['test:uncommitted'].comment = "Test changes since last checkin (only Subversion)"
+
+ Rake::TestTask.new(:units => "db:test:prepare") do |t|
+ t.libs << "test"
+ t.pattern = 'test/unit/**/*_test.rb'
+ t.verbose = true
+ end
+ Rake::Task['test:units'].comment = "Run the unit tests in test/unit"
+
+ Rake::TestTask.new(:functionals => "db:test:prepare") do |t|
+ t.libs << "test"
+ t.pattern = 'test/functional/**/*_test.rb'
+ t.verbose = true
+ end
+ Rake::Task['test:functionals'].comment = "Run the functional tests in test/functional"
+
+ Rake::TestTask.new(:integration => "db:test:prepare") do |t|
+ t.libs << "test"
+ t.pattern = 'test/integration/**/*_test.rb'
+ t.verbose = true
+ end
+ Rake::Task['test:integration'].comment = "Run the integration tests in test/integration"
+
+ Rake::TestTask.new(:plugins => :environment) do |t|
+ t.libs << "test"
+
+ if ENV['PLUGIN']
+ t.pattern = "vendor/plugins/#{ENV['PLUGIN']}/test/**/*_test.rb"
+ else
+ t.pattern = 'vendor/plugins/*/**/test/**/*_test.rb'
+ end
+
+ t.verbose = true
+ end
+ Rake::Task['test:plugins'].comment = "Run the plugin tests in vendor/plugins/*/**/test (or specify with PLUGIN=name)"
+end
diff --git a/vendor/rails-2.0.2/railties/lib/tasks/tmp.rake b/vendor/rails-2.0.2/railties/lib/tasks/tmp.rake
new file mode 100644
index 000000000..b191039d6
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/tasks/tmp.rake
@@ -0,0 +1,37 @@
+namespace :tmp do
+ desc "Clear session, cache, and socket files from tmp/"
+ task :clear => [ "tmp:sessions:clear", "tmp:cache:clear", "tmp:sockets:clear"]
+
+ desc "Creates tmp directories for sessions, cache, and sockets"
+ task :create do
+ FileUtils.mkdir_p(%w( tmp/sessions tmp/cache tmp/sockets tmp/pids ))
+ end
+
+ namespace :sessions do
+ desc "Clears all files in tmp/sessions"
+ task :clear do
+ FileUtils.rm(Dir['tmp/sessions/[^.]*'])
+ end
+ end
+
+ namespace :cache do
+ desc "Clears all files and directories in tmp/cache"
+ task :clear do
+ FileUtils.rm_rf(Dir['tmp/cache/[^.]*'])
+ end
+ end
+
+ namespace :sockets do
+ desc "Clears all files in tmp/sockets"
+ task :clear do
+ FileUtils.rm(Dir['tmp/sockets/[^.]*'])
+ end
+ end
+
+ namespace :pids do
+ desc "Clears all files in tmp/pids"
+ task :clear do
+ FileUtils.rm(Dir['tmp/pids/[^.]*'])
+ end
+ end
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/railties/lib/test_help.rb b/vendor/rails-2.0.2/railties/lib/test_help.rb
new file mode 100644
index 000000000..3b91438c0
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/test_help.rb
@@ -0,0 +1,20 @@
+require_dependency 'application'
+
+# Make double-sure the RAILS_ENV is set to test,
+# so fixtures are loaded to the right database
+silence_warnings { RAILS_ENV = "test" }
+
+require 'test/unit'
+require 'active_support/test_case'
+require 'active_record/fixtures'
+require 'action_controller/test_case'
+require 'action_controller/test_process'
+require 'action_controller/integration'
+require 'action_mailer/test_case' if defined?(ActionMailer)
+
+Test::Unit::TestCase.fixture_path = RAILS_ROOT + "/test/fixtures/"
+ActionController::IntegrationTest.fixture_path = Test::Unit::TestCase.fixture_path
+
+def create_fixtures(*table_names)
+ Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names)
+end
diff --git a/vendor/rails-2.0.2/railties/lib/webrick_server.rb b/vendor/rails-2.0.2/railties/lib/webrick_server.rb
new file mode 100644
index 000000000..ad4ca926b
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/lib/webrick_server.rb
@@ -0,0 +1,165 @@
+# Donated by Florian Gross
+
+require 'webrick'
+require 'cgi'
+require 'stringio'
+require 'dispatcher'
+
+include WEBrick
+
+class CGI #:nodoc:
+ def stdinput
+ @stdin || $stdin
+ end
+
+ def env_table
+ @env_table || ENV
+ end
+
+ def initialize(type = "query", table = nil, stdin = nil)
+ @env_table, @stdin = table, stdin
+
+ if defined?(MOD_RUBY) && !ENV.key?("GATEWAY_INTERFACE")
+ Apache.request.setup_cgi_env
+ end
+
+ extend QueryExtension
+ @multipart = false
+ if defined?(CGI_PARAMS)
+ warn "do not use CGI_PARAMS and CGI_COOKIES"
+ @params = CGI_PARAMS.dup
+ @cookies = CGI_COOKIES.dup
+ else
+ initialize_query() # set @params, @cookies
+ end
+ @output_cookies = nil
+ @output_hidden = nil
+ end
+end
+
+# A custom dispatch servlet for use with WEBrick. It dispatches requests
+# (using the Rails Dispatcher) to the appropriate controller/action. By default,
+# it restricts WEBrick to a managing a single Rails request at a time, but you
+# can change this behavior by setting ActionController::Base.allow_concurrency
+# to true.
+class DispatchServlet < WEBrick::HTTPServlet::AbstractServlet
+ REQUEST_MUTEX = Mutex.new
+
+ # Start the WEBrick server with the given options, mounting the
+ # DispatchServlet at <tt>/</tt>.
+ def self.dispatch(options = {})
+ Socket.do_not_reverse_lookup = true # patch for OS X
+
+ params = { :Port => options[:port].to_i,
+ :ServerType => options[:server_type],
+ :BindAddress => options[:ip] }
+ params[:MimeTypes] = options[:mime_types] if options[:mime_types]
+
+ server = WEBrick::HTTPServer.new(params)
+ server.mount('/', DispatchServlet, options)
+
+ trap("INT") { server.shutdown }
+ server.start
+ end
+
+ def initialize(server, options) #:nodoc:
+ @server_options = options
+ @file_handler = WEBrick::HTTPServlet::FileHandler.new(server, options[:server_root])
+ # Change to the RAILS_ROOT, since Webrick::Daemon.start does a Dir::cwd("/")
+ # OPTIONS['working_directory'] is an absolute path of the RAILS_ROOT, set in railties/lib/commands/servers/webrick.rb
+ Dir.chdir(OPTIONS['working_directory']) if defined?(OPTIONS) && File.directory?(OPTIONS['working_directory'])
+ super
+ end
+
+ def service(req, res) #:nodoc:
+ unless handle_file(req, res)
+ begin
+ REQUEST_MUTEX.lock unless ActionController::Base.allow_concurrency
+ unless handle_dispatch(req, res)
+ raise WEBrick::HTTPStatus::NotFound, "`#{req.path}' not found."
+ end
+ ensure
+ unless ActionController::Base.allow_concurrency
+ REQUEST_MUTEX.unlock if REQUEST_MUTEX.locked?
+ end
+ end
+ end
+ end
+
+ def handle_file(req, res) #:nodoc:
+ begin
+ req = req.dup
+ path = req.path.dup
+
+ # Add .html if the last path piece has no . in it
+ path << '.html' if path != '/' && (%r{(^|/)[^./]+$} =~ path)
+ path.gsub!('+', ' ') # Unescape + since FileHandler doesn't do so.
+
+ req.instance_variable_set(:@path_info, path) # Set the modified path...
+
+ @file_handler.send(:service, req, res)
+ return true
+ rescue HTTPStatus::PartialContent, HTTPStatus::NotModified => err
+ res.set_error(err)
+ return true
+ rescue => err
+ return false
+ end
+ end
+
+ def handle_dispatch(req, res, origin = nil) #:nodoc:
+ data = StringIO.new
+ Dispatcher.dispatch(
+ CGI.new("query", create_env_table(req, origin), StringIO.new(req.body || "")),
+ ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS,
+ data
+ )
+
+ header, body = extract_header_and_body(data)
+
+ set_charset(header)
+ assign_status(res, header)
+ res.cookies.concat(header.delete('set-cookie') || [])
+ header.each { |key, val| res[key] = val.join(", ") }
+
+ res.body = body
+ return true
+ rescue => err
+ p err, err.backtrace
+ return false
+ end
+
+ private
+ def create_env_table(req, origin)
+ env = req.meta_vars.clone
+ env.delete "SCRIPT_NAME"
+ env["QUERY_STRING"] = req.request_uri.query
+ env["REQUEST_URI"] = origin if origin
+ return env
+ end
+
+ def extract_header_and_body(data)
+ data.rewind
+ data = data.read
+
+ raw_header, body = *data.split(/^[\xd\xa]{2}/on, 2)
+ header = WEBrick::HTTPUtils::parse_header(raw_header)
+
+ return header, body
+ end
+
+ def set_charset(header)
+ ct = header["content-type"]
+ if ct.any? { |x| x =~ /^text\// } && ! ct.any? { |x| x =~ /charset=/ }
+ ch = @server_options[:charset] || "UTF-8"
+ ct.find { |x| x =~ /^text\// } << ("; charset=" + ch)
+ end
+ end
+
+ def assign_status(res, header)
+ if /^(\d+)/ =~ header['status'][0]
+ res.status = $1.to_i
+ header.delete('status')
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/test/abstract_unit.rb b/vendor/rails-2.0.2/railties/test/abstract_unit.rb
new file mode 100644
index 000000000..e1ce32da6
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/test/abstract_unit.rb
@@ -0,0 +1,24 @@
+$:.unshift File.dirname(__FILE__) + "/../../activesupport/lib"
+$:.unshift File.dirname(__FILE__) + "/../../actionpack/lib"
+$:.unshift File.dirname(__FILE__) + "/../lib"
+$:.unshift File.dirname(__FILE__) + "/../builtin/rails_info"
+
+require 'test/unit'
+require 'stringio'
+require 'active_support'
+
+# Wrap tests that use Mocha and skip if unavailable.
+def uses_mocha(test_name)
+ require 'rubygems'
+ gem 'mocha', '>= 0.5.5'
+ require 'mocha'
+ yield
+rescue LoadError
+ $stderr.puts "Skipping #{test_name} tests. `gem install mocha` and try again."
+end
+
+if defined?(RAILS_ROOT)
+ RAILS_ROOT.replace File.dirname(__FILE__)
+else
+ RAILS_ROOT = File.dirname(__FILE__)
+end
diff --git a/vendor/rails-2.0.2/railties/test/boot_test.rb b/vendor/rails-2.0.2/railties/test/boot_test.rb
new file mode 100644
index 000000000..36fae307c
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/test/boot_test.rb
@@ -0,0 +1,179 @@
+require "#{File.dirname(__FILE__)}/abstract_unit"
+require 'initializer'
+require "#{File.dirname(__FILE__)}/../environments/boot"
+
+uses_mocha 'boot tests' do
+
+class BootTest < Test::Unit::TestCase
+ def test_boot_returns_if_booted
+ Rails.expects(:booted?).returns(true)
+ Rails.expects(:pick_boot).never
+ assert_nil Rails.boot!
+ end
+
+ def test_boot_preinitializes_then_picks_and_runs_if_not_booted
+ Rails.expects(:booted?).returns(false)
+ Rails.expects(:preinitialize)
+ Rails.expects(:pick_boot).returns(mock(:run => 'result'))
+ assert_equal 'result', Rails.boot!
+ end
+
+ def test_preinitialize_does_not_raise_exception_if_preinitializer_file_does_not_exist
+ Rails.stubs(:preinitializer_path).returns('/there/is/no/such/file')
+
+ assert_nothing_raised { Rails.preinitialize }
+ end
+
+ def test_load_preinitializer_loads_preinitializer_file
+ Rails.stubs(:preinitializer_path).returns("#{File.dirname(__FILE__)}/fixtures/environment_with_constant.rb")
+
+ assert_nil $initialize_test_set_from_env
+ Rails.preinitialize
+ assert_equal "success", $initialize_test_set_from_env
+ ensure
+ $initialize_test_set_from_env = nil
+ end
+
+ def test_boot_vendor_rails_by_default
+ Rails.expects(:booted?).returns(false)
+ File.expects(:exist?).with("#{RAILS_ROOT}/vendor/rails").returns(true)
+ Rails::VendorBoot.any_instance.expects(:run).returns('result')
+ assert_equal 'result', Rails.boot!
+ end
+
+ def test_boot_gem_rails_otherwise
+ Rails.expects(:booted?).returns(false)
+ File.expects(:exist?).with("#{RAILS_ROOT}/vendor/rails").returns(false)
+ Rails::GemBoot.any_instance.expects(:run).returns('result')
+ assert_equal 'result', Rails.boot!
+ end
+
+ def test_run_loads_initializer_and_sets_load_path
+ boot = Rails::Boot.new
+ boot.expects(:load_initializer)
+ Rails::Initializer.expects(:run).with(:set_load_path)
+ boot.run
+ end
+end
+
+class VendorBootTest < Test::Unit::TestCase
+ include Rails
+
+ def test_load_initializer_requires_from_vendor_rails
+ boot = VendorBoot.new
+ boot.expects(:require).with("#{RAILS_ROOT}/vendor/rails/railties/lib/initializer")
+ boot.load_initializer
+ end
+end
+
+class GemBootTest < Test::Unit::TestCase
+ include Rails
+
+ def test_load_initializer_loads_rubygems_and_the_rails_gem
+ boot = GemBoot.new
+ GemBoot.expects(:load_rubygems)
+ boot.expects(:load_rails_gem)
+ boot.expects(:require).with('initializer')
+ boot.load_initializer
+ end
+
+ def test_load_rubygems_exits_with_error_if_missing
+ GemBoot.expects(:require).with('rubygems').raises(LoadError, 'missing rubygems')
+ STDERR.expects(:puts)
+ GemBoot.expects(:exit).with(1)
+ GemBoot.load_rubygems
+ end
+
+ def test_load_rubygems_exits_with_error_if_too_old
+ GemBoot.stubs(:rubygems_version).returns('0.0.1')
+ GemBoot.expects(:require).with('rubygems').returns(true)
+ STDERR.expects(:puts)
+ GemBoot.expects(:exit).with(1)
+ GemBoot.load_rubygems
+ end
+
+ def test_load_rails_gem_activates_specific_gem_if_version_given
+ GemBoot.stubs(:gem_version).returns('0.0.1')
+
+ boot = GemBoot.new
+ boot.expects(:gem).with('rails', '0.0.1')
+ boot.load_rails_gem
+ end
+
+ def test_load_rails_gem_activates_latest_gem_if_no_version_given
+ GemBoot.stubs(:gem_version).returns(nil)
+
+ boot = GemBoot.new
+ boot.expects(:gem).with('rails')
+ boot.load_rails_gem
+ end
+
+ def test_load_rails_gem_exits_with_error_if_missing
+ GemBoot.stubs(:gem_version).returns('0.0.1')
+
+ boot = GemBoot.new
+ boot.expects(:gem).with('rails', '0.0.1').raises(Gem::LoadError, 'missing rails 0.0.1 gem')
+ STDERR.expects(:puts)
+ boot.expects(:exit).with(1)
+ boot.load_rails_gem
+ end
+end
+
+end # uses_mocha
+
+
+class ParseGemVersionTest < Test::Unit::TestCase
+ def test_should_return_nil_if_no_lines_are_passed
+ assert_equal nil, parse('')
+ assert_equal nil, parse(nil)
+ end
+
+ def test_should_accept_either_single_or_double_quotes
+ assert_equal "1.2.3", parse("RAILS_GEM_VERSION = '1.2.3'")
+ assert_equal "1.2.3", parse('RAILS_GEM_VERSION = "1.2.3"')
+ end
+
+ def test_should_return_nil_if_no_lines_match
+ assert_equal nil, parse('nothing matches on this line\nor on this line')
+ end
+
+ def test_should_parse_with_no_leading_space
+ assert_equal "1.2.3", parse("RAILS_GEM_VERSION = '1.2.3' unless defined? RAILS_GEM_VERSION")
+ assert_equal "1.2.3", parse("RAILS_GEM_VERSION = '1.2.3'")
+ end
+
+ def test_should_parse_with_any_number_of_leading_spaces
+ assert_equal nil, parse([])
+ assert_equal "1.2.3", parse(" RAILS_GEM_VERSION = '1.2.3' unless defined? RAILS_GEM_VERSION")
+ assert_equal "1.2.3", parse(" RAILS_GEM_VERSION = '1.2.3' unless defined? RAILS_GEM_VERSION")
+ assert_equal "1.2.3", parse(" RAILS_GEM_VERSION = '1.2.3'")
+ assert_equal "1.2.3", parse(" RAILS_GEM_VERSION = '1.2.3'")
+ end
+
+ def test_should_ignore_unrelated_comments
+ assert_equal "1.2.3", parse("# comment\nRAILS_GEM_VERSION = '1.2.3'\n# comment")
+ end
+
+ def test_should_ignore_commented_version_lines
+ assert_equal "1.2.3", parse("#RAILS_GEM_VERSION = '9.8.7'\nRAILS_GEM_VERSION = '1.2.3'")
+ assert_equal "1.2.3", parse("# RAILS_GEM_VERSION = '9.8.7'\nRAILS_GEM_VERSION = '1.2.3'")
+ assert_equal "1.2.3", parse("RAILS_GEM_VERSION = '1.2.3'\n# RAILS_GEM_VERSION = '9.8.7'")
+ end
+
+ def test_should_allow_advanced_rubygems_version_specifications
+ # See http://rubygems.org/read/chapter/16
+ assert_equal "=1.2.3", parse("RAILS_GEM_VERSION = '=1.2.3'") # equal sign
+ assert_equal "= 1.2.3", parse("RAILS_GEM_VERSION = '= 1.2.3'") # with space
+ assert_equal "!=1.2.3", parse("RAILS_GEM_VERSION = '!=1.2.3'") # not equal
+ assert_equal ">1.2.3", parse("RAILS_GEM_VERSION = '>1.2.3'") # greater than
+ assert_equal "<1.2.3", parse("RAILS_GEM_VERSION = '<1.2.3'") # less than
+ assert_equal ">=1.2.3", parse("RAILS_GEM_VERSION = '>=1.2.3'") # greater than or equal
+ assert_equal "<=1.2.3", parse("RAILS_GEM_VERSION = '<=1.2.3'") # less than or equal
+ assert_equal "~>1.2.3.0", parse("RAILS_GEM_VERSION = '~>1.2.3.0'") # approximately greater than
+ end
+
+ private
+ def parse(text)
+ Rails::GemBoot.parse_gem_version(text)
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/test/console_app_test.rb b/vendor/rails-2.0.2/railties/test/console_app_test.rb
new file mode 100644
index 000000000..ac499e0f1
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/test/console_app_test.rb
@@ -0,0 +1,29 @@
+require File.dirname(__FILE__) + '/abstract_unit'
+
+require 'action_controller' # console_app uses 'action_controller/integration'
+
+unless defined? ApplicationController
+ class ApplicationController < ActionController::Base; end
+end
+
+require 'dispatcher'
+require 'console_app'
+
+# console_app sets Test::Unit.run to work around the at_exit hook in test/unit, which kills IRB
+Test::Unit.run = false
+
+class ConsoleAppTest < Test::Unit::TestCase
+ def test_reload_should_fire_preparation_callbacks
+ a = b = c = nil
+
+ Dispatcher.to_prepare { a = b = c = 1 }
+ Dispatcher.to_prepare { b = c = 2 }
+ Dispatcher.to_prepare { c = 3 }
+
+ reload!
+
+ assert_equal 1, a
+ assert_equal 2, b
+ assert_equal 3, c
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/test/fcgi_dispatcher_test.rb b/vendor/rails-2.0.2/railties/test/fcgi_dispatcher_test.rb
new file mode 100644
index 000000000..7949cb652
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/test/fcgi_dispatcher_test.rb
@@ -0,0 +1,265 @@
+require File.dirname(__FILE__) + "/abstract_unit"
+
+uses_mocha 'fcgi dispatcher tests' do
+
+require 'fcgi_handler'
+
+module ActionController; module Routing; module Routes; end end end
+
+class RailsFCGIHandlerTest < Test::Unit::TestCase
+ def setup
+ @log = StringIO.new
+ @handler = RailsFCGIHandler.new(@log)
+ end
+
+ def test_process_restart
+ cgi = mock
+ FCGI.stubs(:each_cgi).yields(cgi)
+
+ @handler.expects(:process_request).once
+ @handler.expects(:dispatcher_error).never
+
+ @handler.expects(:when_ready).returns(:restart)
+ @handler.expects(:close_connection).with(cgi)
+ @handler.expects(:reload!).never
+ @handler.expects(:restart!)
+
+ @handler.process!
+ end
+
+ def test_process_exit
+ cgi = mock
+ FCGI.stubs(:each_cgi).yields(cgi)
+
+ @handler.expects(:process_request).once
+ @handler.expects(:dispatcher_error).never
+
+ @handler.expects(:when_ready).returns(:exit)
+ @handler.expects(:close_connection).with(cgi)
+ @handler.expects(:reload!).never
+ @handler.expects(:restart!).never
+
+ @handler.process!
+ end
+
+ def test_process_with_system_exit_exception
+ cgi = mock
+ FCGI.stubs(:each_cgi).yields(cgi)
+
+ @handler.expects(:process_request).once.raises(SystemExit)
+ @handler.stubs(:dispatcher_log)
+ @handler.expects(:dispatcher_log).with(:info, regexp_matches(/^stopping/))
+ @handler.expects(:dispatcher_error).never
+
+ @handler.expects(:when_ready).never
+ @handler.expects(:close_connection).never
+ @handler.expects(:reload!).never
+ @handler.expects(:restart!).never
+
+ @handler.process!
+ end
+
+ def test_restart_handler
+ @handler.expects(:dispatcher_log).with(:info, "asked to restart ASAP")
+
+ @handler.send(:restart_handler, nil)
+ assert_equal :restart, @handler.when_ready
+ end
+
+ def test_install_signal_handler_should_log_on_bad_signal
+ @handler.stubs(:trap).raises(ArgumentError)
+
+ @handler.expects(:dispatcher_log).with(:warn, "Ignoring unsupported signal CHEESECAKE.")
+ @handler.send(:install_signal_handler, "CHEESECAKE", nil)
+ end
+
+ def test_reload
+ @handler.expects(:restore!)
+ @handler.expects(:dispatcher_log).with(:info, "reloaded")
+
+ @handler.send(:reload!)
+ assert_nil @handler.when_ready
+ end
+
+
+ def test_reload_runs_gc_when_gc_request_period_set
+ @handler.expects(:run_gc!)
+ @handler.expects(:restore!)
+ @handler.expects(:dispatcher_log).with(:info, "reloaded")
+ @handler.gc_request_period = 10
+ @handler.send(:reload!)
+ end
+
+ def test_reload_doesnt_run_gc_if_gc_request_period_isnt_set
+ @handler.expects(:run_gc!).never
+ @handler.expects(:restore!)
+ @handler.expects(:dispatcher_log).with(:info, "reloaded")
+ @handler.send(:reload!)
+ end
+
+ def test_restart!
+ @handler.expects(:dispatcher_log).with(:info, "restarted")
+ @handler.expects(:exec).returns('restarted')
+ assert_equal 'restarted', @handler.send(:restart!)
+ end
+
+ def test_restore!
+ $".expects(:replace)
+ Dispatcher.expects(:reset_application!)
+ ActionController::Routing::Routes.expects(:reload)
+ @handler.send(:restore!)
+ end
+
+ def test_uninterrupted_processing
+ cgi = mock
+ FCGI.expects(:each_cgi).yields(cgi)
+ @handler.expects(:process_request).with(cgi)
+
+ @handler.process!
+
+ assert_nil @handler.when_ready
+ end
+end
+
+
+class RailsFCGIHandlerSignalsTest < Test::Unit::TestCase
+ def setup
+ @log = StringIO.new
+ @handler = RailsFCGIHandler.new(@log)
+ end
+
+ def test_interrupted_via_HUP_when_not_in_request
+ cgi = mock
+ FCGI.expects(:each_cgi).once.yields(cgi)
+ @handler.expects(:gc_countdown).returns { Process.kill 'HUP', $$ }
+
+ @handler.expects(:reload!).once
+ @handler.expects(:close_connection).never
+ @handler.expects(:exit).never
+
+ @handler.process!
+ assert_equal :reload, @handler.when_ready
+ end
+
+ def test_interrupted_via_HUP_when_in_request
+ cgi = mock
+ FCGI.expects(:each_cgi).once.yields(cgi)
+ Dispatcher.expects(:dispatch).with(cgi).returns { Process.kill 'HUP', $$ }
+
+ @handler.expects(:reload!).once
+ @handler.expects(:close_connection).never
+ @handler.expects(:exit).never
+
+ @handler.process!
+ assert_equal :reload, @handler.when_ready
+ end
+
+ def test_interrupted_via_USR1_when_not_in_request
+ cgi = mock
+ FCGI.expects(:each_cgi).once.yields(cgi)
+ @handler.expects(:gc_countdown).returns { Process.kill 'USR1', $$ }
+ @handler.expects(:exit_handler).never
+
+ @handler.expects(:reload!).never
+ @handler.expects(:close_connection).with(cgi).once
+ @handler.expects(:exit).never
+
+ @handler.process!
+ assert_nil @handler.when_ready
+ end
+
+ def test_interrupted_via_USR1_when_in_request
+ cgi = mock
+ FCGI.expects(:each_cgi).once.yields(cgi)
+ Dispatcher.expects(:dispatch).with(cgi).returns { Process.kill 'USR1', $$ }
+
+ @handler.expects(:reload!).never
+ @handler.expects(:close_connection).with(cgi).once
+ @handler.expects(:exit).never
+
+ @handler.process!
+ assert_equal :exit, @handler.when_ready
+ end
+
+ def test_interrupted_via_TERM
+ cgi = mock
+ FCGI.expects(:each_cgi).once.yields(cgi)
+ Dispatcher.expects(:dispatch).with(cgi).returns { Process.kill 'TERM', $$ }
+
+ @handler.expects(:reload!).never
+ @handler.expects(:close_connection).never
+
+ @handler.process!
+ assert_nil @handler.when_ready
+ end
+
+ def test_runtime_exception_in_fcgi
+ error = RuntimeError.new('foo')
+ FCGI.expects(:each_cgi).times(2).raises(error)
+ @handler.expects(:dispatcher_error).with(error, regexp_matches(/^retrying/))
+ @handler.expects(:dispatcher_error).with(error, regexp_matches(/^stopping/))
+ @handler.process!
+ end
+
+ def test_runtime_error_in_dispatcher
+ cgi = mock
+ error = RuntimeError.new('foo')
+ FCGI.expects(:each_cgi).once.yields(cgi)
+ Dispatcher.expects(:dispatch).once.with(cgi).raises(error)
+ @handler.expects(:dispatcher_error).with(error, regexp_matches(/^unhandled/))
+ @handler.process!
+ end
+
+ def test_signal_exception_in_fcgi
+ error = SignalException.new('USR2')
+ FCGI.expects(:each_cgi).once.raises(error)
+ @handler.expects(:dispatcher_error).with(error, regexp_matches(/^stopping/))
+ @handler.process!
+ end
+
+ def test_signal_exception_in_dispatcher
+ cgi = mock
+ error = SignalException.new('USR2')
+ FCGI.expects(:each_cgi).once.yields(cgi)
+ Dispatcher.expects(:dispatch).once.with(cgi).raises(error)
+ @handler.expects(:dispatcher_error).with(error, regexp_matches(/^stopping/))
+ @handler.process!
+ end
+end
+
+
+class RailsFCGIHandlerPeriodicGCTest < Test::Unit::TestCase
+ def setup
+ @log = StringIO.new
+ end
+
+ def teardown
+ GC.enable
+ end
+
+ def test_normal_gc
+ @handler = RailsFCGIHandler.new(@log)
+ assert_nil @handler.gc_request_period
+
+ # When GC is enabled, GC.disable disables and returns false.
+ assert_equal false, GC.disable
+ end
+
+ def test_periodic_gc
+ @handler = RailsFCGIHandler.new(@log, 10)
+ assert_equal 10, @handler.gc_request_period
+
+ cgi = mock
+ FCGI.expects(:each_cgi).times(10).yields(cgi)
+ Dispatcher.expects(:dispatch).times(10).with(cgi)
+
+ @handler.expects(:run_gc!).never
+ 9.times { @handler.process! }
+ @handler.expects(:run_gc!).once
+ @handler.process!
+
+ assert_nil @handler.when_ready
+ end
+end
+
+end # uses_mocha
diff --git a/vendor/rails-2.0.2/railties/test/fixtures/environment_with_constant.rb b/vendor/rails-2.0.2/railties/test/fixtures/environment_with_constant.rb
new file mode 100644
index 000000000..23e1f7afd
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/test/fixtures/environment_with_constant.rb
@@ -0,0 +1 @@
+$initialize_test_set_from_env = 'success'
diff --git a/vendor/rails-2.0.2/railties/test/fixtures/lib/generators/missing_class/missing_class_generator.rb b/vendor/rails-2.0.2/railties/test/fixtures/lib/generators/missing_class/missing_class_generator.rb
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/test/fixtures/lib/generators/missing_class/missing_class_generator.rb
diff --git a/vendor/rails-2.0.2/railties/test/fixtures/lib/generators/working/working_generator.rb b/vendor/rails-2.0.2/railties/test/fixtures/lib/generators/working/working_generator.rb
new file mode 100644
index 000000000..465b34319
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/test/fixtures/lib/generators/working/working_generator.rb
@@ -0,0 +1,2 @@
+class WorkingGenerator < Rails::Generator::NamedBase
+end
diff --git a/vendor/rails-2.0.2/railties/test/fixtures/plugins/default/plugin_with_no_lib_dir/init.rb b/vendor/rails-2.0.2/railties/test/fixtures/plugins/default/plugin_with_no_lib_dir/init.rb
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/test/fixtures/plugins/default/plugin_with_no_lib_dir/init.rb
diff --git a/vendor/rails-2.0.2/railties/test/fixtures/plugins/default/stubby/init.rb b/vendor/rails-2.0.2/railties/test/fixtures/plugins/default/stubby/init.rb
new file mode 100644
index 000000000..81beeb0d3
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/test/fixtures/plugins/default/stubby/init.rb
@@ -0,0 +1,7 @@
+# I have access to my directory and the Rails config.
+raise 'directory expected but undefined in init.rb' unless defined? directory
+raise 'config expected but undefined in init.rb' unless defined? config
+
+# My lib/ dir must be in the load path.
+require 'stubby_mixin'
+raise 'missing mixin from my lib/ dir' unless defined? StubbyMixin
diff --git a/vendor/rails-2.0.2/railties/test/fixtures/plugins/default/stubby/lib/stubby_mixin.rb b/vendor/rails-2.0.2/railties/test/fixtures/plugins/default/stubby/lib/stubby_mixin.rb
new file mode 100644
index 000000000..2d569e500
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/test/fixtures/plugins/default/stubby/lib/stubby_mixin.rb
@@ -0,0 +1,2 @@
+module StubbyMixin
+end
diff --git a/vendor/rails-2.0.2/railties/test/generators/generator_test_helper.rb b/vendor/rails-2.0.2/railties/test/generators/generator_test_helper.rb
new file mode 100644
index 000000000..3af5886a0
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/test/generators/generator_test_helper.rb
@@ -0,0 +1,195 @@
+module GeneratorTestHelper
+ # Instantiates the Generator
+ def build_generator(name,params)
+ Rails::Generator::Base.instance(name,params)
+ end
+
+ # Runs the create command (like the command line does)
+ def run_generator(name,params)
+ silence_generator do
+ build_generator(name,params).command(:create).invoke!
+ end
+ end
+
+ # Silences the logger temporarily and returns the output as a String
+ def silence_generator
+ logger_original=Rails::Generator::Base.logger
+ myout=StringIO.new
+ Rails::Generator::Base.logger=Rails::Generator::SimpleLogger.new(myout)
+ yield if block_given?
+ Rails::Generator::Base.logger=logger_original
+ myout.string
+ end
+
+ # asserts that the given controller was generated.
+ # It takes a name or symbol without the <tt>_controller</tt> part and an optional super class.
+ # The contents of the class source file is passed to a block.
+ def assert_generated_controller_for(name,parent="ApplicationController")
+ assert_generated_class "app/controllers/#{name.to_s.underscore}_controller",parent do |body|
+ yield body if block_given?
+ end
+ end
+
+ # asserts that the given model was generated.
+ # It takes a name or symbol and an optional super class.
+ # the contents of the class source file is passed to a block.
+ def assert_generated_model_for(name,parent="ActiveRecord::Base")
+ assert_generated_class "app/models/#{name.to_s.underscore}",parent do |body|
+ yield body if block_given?
+ end
+ end
+
+ # asserts that the given helper was generated.
+ # It takes a name or symbol without the <tt>_helper</tt> part
+ # the contents of the module source file is passed to a block.
+ def assert_generated_helper_for(name)
+ assert_generated_module "app/helpers/#{name.to_s.underscore}_helper" do |body|
+ yield body if block_given?
+ end
+ end
+
+ # asserts that the given functional test was generated.
+ # It takes a name or symbol without the <tt>_controller_test</tt> part and an optional super class.
+ # the contents of the class source file is passed to a block.
+ def assert_generated_functional_test_for(name,parent="Test::Unit::TestCase")
+ assert_generated_class "test/functional/#{name.to_s.underscore}_controller_test",parent do |body|
+ yield body if block_given?
+ end
+ end
+
+ # asserts that the given unit test was generated.
+ # It takes a name or symbol without the <tt>_test</tt> part and an optional super class.
+ # the contents of the class source file is passed to a block.
+ def assert_generated_unit_test_for(name,parent="Test::Unit::TestCase")
+ assert_generated_class "test/unit/#{name.to_s.underscore}_test",parent do |body|
+ yield body if block_given?
+ end
+ end
+
+ # asserts that the given file was generated.
+ # the contents of the file is passed to a block.
+ def assert_generated_file(path)
+ assert_file_exists(path)
+ File.open("#{RAILS_ROOT}/#{path}") do |f|
+ yield f.read if block_given?
+ end
+ end
+
+ # asserts that the given file exists
+ def assert_file_exists(path)
+ assert File.exist?("#{RAILS_ROOT}/#{path}"),"The file '#{path}' should exist"
+ end
+
+ # asserts that the given class source file was generated.
+ # It takes a path without the <tt>.rb</tt> part and an optional super class.
+ # the contents of the class source file is passed to a block.
+ def assert_generated_class(path,parent=nil)
+ path=~/\/?(\d+_)?(\w+)$/
+ class_name=$2.camelize
+ assert_generated_file("#{path}.rb") do |body|
+ assert body=~/class #{class_name}#{parent.nil? ? '':" < #{parent}"}/,"the file '#{path}.rb' should be a class"
+ yield body if block_given?
+ end
+ end
+
+ # asserts that the given module source file was generated.
+ # It takes a path without the <tt>.rb</tt> part.
+ # the contents of the class source file is passed to a block.
+ def assert_generated_module(path)
+ path=~/\/?(\w+)$/
+ module_name=$1.camelize
+ assert_generated_file("#{path}.rb") do |body|
+ assert body=~/module #{module_name}/,"the file '#{path}.rb' should be a module"
+ yield body if block_given?
+ end
+ end
+
+ # asserts that the given css stylesheet file was generated.
+ # It takes a path without the <tt>.css</tt> part.
+ # the contents of the stylesheet source file is passed to a block.
+ def assert_generated_stylesheet(path)
+ assert_generated_file("public/stylesheets/#{path}.css") do |body|
+ yield body if block_given?
+ end
+ end
+
+ # asserts that the given yaml file was generated.
+ # It takes a path without the <tt>.yml</tt> part.
+ # the parsed yaml tree is passed to a block.
+ def assert_generated_yaml(path)
+ assert_generated_file("#{path}.yml") do |body|
+ assert yaml=YAML.load(body)
+ yield yaml if block_given?
+ end
+ end
+
+ # asserts that the given fixtures yaml file was generated.
+ # It takes a fixture name without the <tt>.yml</tt> part.
+ # the parsed yaml tree is passed to a block.
+ def assert_generated_fixtures_for(name)
+ assert_generated_yaml "test/fixtures/#{name.to_s.underscore}" do |yaml|
+ assert_generated_timestamps(yaml)
+ yield yaml if block_given?
+ end
+ end
+
+ # asserts that the given views were generated.
+ # It takes a controller name and a list of views (including extensions).
+ # The body of each view is passed to a block
+ def assert_generated_views_for(name,*actions)
+ actions.each do |action|
+ assert_generated_file("app/views/#{name.to_s.underscore}/#{action.to_s}") do |body|
+ yield body if block_given?
+ end
+ end
+ end
+
+ # asserts that the given migration file was generated.
+ # It takes the name of the migration as a parameter.
+ # The migration body is passed to a block.
+ def assert_generated_migration(name,parent="ActiveRecord::Migration")
+ assert_generated_class "db/migrate/001_#{name.to_s.underscore}",parent do |body|
+ assert body=~/timestamps/, "should have timestamps defined"
+ yield body if block_given?
+ end
+ end
+
+ # Asserts that the given migration file was not generated.
+ # It takes the name of the migration as a parameter.
+ def assert_skipped_migration(name)
+ migration_file = "#{RAILS_ROOT}/db/migrate/001_#{name.to_s.underscore}.rb"
+ assert !File.exist?(migration_file), "should not create migration #{migration_file}"
+ end
+
+ # asserts that the given resource was added to the routes.
+ def assert_added_route_for(name)
+ assert_generated_file("config/routes.rb") do |body|
+ assert body=~/map.resources :#{name.to_s.underscore}/,"should add route for :#{name.to_s.underscore}"
+ end
+ end
+
+ # asserts that the given methods are defined in the body.
+ # This does assume standard rails code conventions with regards to the source code.
+ # The body of each individual method is passed to a block.
+ def assert_has_method(body,*methods)
+ methods.each do |name|
+ assert body=~/^ def #{name.to_s}\n((\n| .*\n)*) end/,"should have method #{name.to_s}"
+ yield( name, $1 ) if block_given?
+ end
+ end
+
+ # asserts that the given column is defined in the migration
+ def assert_generated_column(body,name,type)
+ assert body=~/t\.#{type.to_s} :#{name.to_s}/, "should have column #{name.to_s} defined"
+ end
+
+ private
+ # asserts that the default timestamps are created in the fixture
+ def assert_generated_timestamps(yaml)
+ yaml.values.each do |v|
+ ["created_at", "updated_at"].each do |field|
+ assert v.keys.include?(field), "should have #{field} field by default"
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/test/generators/rails_model_generator_test.rb b/vendor/rails-2.0.2/railties/test/generators/rails_model_generator_test.rb
new file mode 100644
index 000000000..a1637c4cd
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/test/generators/rails_model_generator_test.rb
@@ -0,0 +1,109 @@
+require 'test/unit'
+
+# Optionally load RubyGems
+begin
+ require 'rubygems'
+rescue LoadError
+end
+
+# Mock out what we need from AR::Base
+module ActiveRecord
+ class Base
+ class << self
+ attr_accessor :pluralize_table_names
+ end
+ self.pluralize_table_names = true
+ end
+
+ module ConnectionAdapters
+ class Column
+ attr_reader :name, :default, :type, :limit, :null, :sql_type, :precision, :scale
+ def initialize(name, default, sql_type=nil)
+ @namename
+ @default=default
+ @type=@sql_type=sql_type
+ end
+
+ def human_name
+ @name.humanize
+ end
+ end
+ end
+end
+
+# Mock up necessities from ActionView
+module ActionView
+ module Helpers
+ module ActionRecordHelper; end
+ class InstanceTag; end
+ end
+end
+
+# Set RAILS_ROOT appropriately fixture generation
+tmp_dir="#{File.dirname(__FILE__)}/../fixtures/tmp"
+if defined?(RAILS_ROOT)
+ RAILS_ROOT.replace(tmp_dir)
+else
+ RAILS_ROOT=tmp_dir
+end
+Dir.mkdir(RAILS_ROOT) unless File.exist?(RAILS_ROOT)
+
+$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../../lib"
+require 'rails_generator'
+require "#{File.dirname(__FILE__)}/generator_test_helper"
+
+class RailsModelGeneratorTest < Test::Unit::TestCase
+ include GeneratorTestHelper
+
+ def setup
+ ActiveRecord::Base.pluralize_table_names = true
+ Dir.mkdir("#{RAILS_ROOT}/app") unless File.exist?("#{RAILS_ROOT}/app")
+ Dir.mkdir("#{RAILS_ROOT}/app/views") unless File.exist?("#{RAILS_ROOT}/app/views")
+ Dir.mkdir("#{RAILS_ROOT}/app/views/layouts") unless File.exist?("#{RAILS_ROOT}/app/views/layouts")
+ Dir.mkdir("#{RAILS_ROOT}/config") unless File.exist?("#{RAILS_ROOT}/config")
+ Dir.mkdir("#{RAILS_ROOT}/db") unless File.exist?("#{RAILS_ROOT}/db")
+ Dir.mkdir("#{RAILS_ROOT}/test") unless File.exist?("#{RAILS_ROOT}/test")
+ Dir.mkdir("#{RAILS_ROOT}/test/fixtures") unless File.exist?("#{RAILS_ROOT}/test/fixtures")
+ Dir.mkdir("#{RAILS_ROOT}/public") unless File.exist?("#{RAILS_ROOT}/public")
+ Dir.mkdir("#{RAILS_ROOT}/public/stylesheets") unless File.exist?("#{RAILS_ROOT}/public/stylesheets")
+ File.open("#{RAILS_ROOT}/config/routes.rb", 'w') do |f|
+ f<<"ActionController::Routing::Routes.draw do |map|\n\nend\n"
+ end
+ end
+
+ def teardown
+ FileUtils.rm_rf "#{RAILS_ROOT}/app"
+ FileUtils.rm_rf "#{RAILS_ROOT}/test"
+ FileUtils.rm_rf "#{RAILS_ROOT}/config"
+ FileUtils.rm_rf "#{RAILS_ROOT}/db"
+ FileUtils.rm_rf "#{RAILS_ROOT}/public"
+ end
+
+ def test_model_generates_resources
+ run_generator('model', %w(Product))
+
+ assert_generated_model_for :product
+ assert_generated_fixtures_for :products
+ assert_generated_migration :create_products
+ end
+
+ def test_model_skip_migration_skips_migration
+ run_generator('model', %w(Product --skip-migration))
+
+ assert_generated_model_for :product
+ assert_generated_fixtures_for :products
+ assert_skipped_migration :create_products
+ end
+
+ def test_model_with_attributes_generates_resources_with_attributes
+ run_generator('model', %w(Product name:string supplier_id:integer created_at:timestamp))
+
+ assert_generated_model_for :product
+ assert_generated_fixtures_for :products
+ assert_generated_migration :create_products do |t|
+ assert_generated_column t, :name, :string
+ assert_generated_column t, :supplier_id, :integer
+ assert_generated_column t, :created_at, :timestamp
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/test/generators/rails_resource_generator_test.rb b/vendor/rails-2.0.2/railties/test/generators/rails_resource_generator_test.rb
new file mode 100644
index 000000000..63cd284d3
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/test/generators/rails_resource_generator_test.rb
@@ -0,0 +1,106 @@
+require 'test/unit'
+
+# Optionally load RubyGems
+begin
+ require 'rubygems'
+rescue LoadError
+end
+
+# Mock out what we need from AR::Base
+module ActiveRecord
+ class Base
+ class << self
+ attr_accessor :pluralize_table_names
+ end
+ self.pluralize_table_names = true
+ end
+
+ module ConnectionAdapters
+ class Column
+ attr_reader :name, :default, :type, :limit, :null, :sql_type, :precision, :scale
+ def initialize(name, default, sql_type=nil)
+ @namename
+ @default=default
+ @type=@sql_type=sql_type
+ end
+
+ def human_name
+ @name.humanize
+ end
+ end
+ end
+end
+
+# Mock up necessities from ActionView
+module ActionView
+ module Helpers
+ module ActionRecordHelper; end
+ class InstanceTag; end
+ end
+end
+
+# Set RAILS_ROOT appropriately fixture generation
+tmp_dir="#{File.dirname(__FILE__)}/../fixtures/tmp"
+if defined?(RAILS_ROOT)
+ RAILS_ROOT.replace(tmp_dir)
+else
+ RAILS_ROOT=tmp_dir
+end
+Dir.mkdir(RAILS_ROOT) unless File.exist?(RAILS_ROOT)
+
+$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../../lib"
+require 'rails_generator'
+require "#{File.dirname(__FILE__)}/generator_test_helper"
+
+class RailsResourceGeneratorTest < Test::Unit::TestCase
+ include GeneratorTestHelper
+
+ def setup
+ ActiveRecord::Base.pluralize_table_names = true
+ Dir.mkdir("#{RAILS_ROOT}/app") unless File.exist?("#{RAILS_ROOT}/app")
+ Dir.mkdir("#{RAILS_ROOT}/app/views") unless File.exist?("#{RAILS_ROOT}/app/views")
+ Dir.mkdir("#{RAILS_ROOT}/app/views/layouts") unless File.exist?("#{RAILS_ROOT}/app/views/layouts")
+ Dir.mkdir("#{RAILS_ROOT}/config") unless File.exist?("#{RAILS_ROOT}/config")
+ Dir.mkdir("#{RAILS_ROOT}/db") unless File.exist?("#{RAILS_ROOT}/db")
+ Dir.mkdir("#{RAILS_ROOT}/test") unless File.exist?("#{RAILS_ROOT}/test")
+ Dir.mkdir("#{RAILS_ROOT}/test/fixtures") unless File.exist?("#{RAILS_ROOT}/test/fixtures")
+ Dir.mkdir("#{RAILS_ROOT}/public") unless File.exist?("#{RAILS_ROOT}/public")
+ Dir.mkdir("#{RAILS_ROOT}/public/stylesheets") unless File.exist?("#{RAILS_ROOT}/public/stylesheets")
+ File.open("#{RAILS_ROOT}/config/routes.rb", 'w') do |f|
+ f<<"ActionController::Routing::Routes.draw do |map|\n\nend\n"
+ end
+ end
+
+ def teardown
+ FileUtils.rm_rf "#{RAILS_ROOT}/app"
+ FileUtils.rm_rf "#{RAILS_ROOT}/test"
+ FileUtils.rm_rf "#{RAILS_ROOT}/config"
+ FileUtils.rm_rf "#{RAILS_ROOT}/db"
+ FileUtils.rm_rf "#{RAILS_ROOT}/public"
+ end
+
+ def test_resource_generates_resources
+ run_generator('scaffold', %w(Product))
+
+ assert_generated_controller_for :products
+ assert_generated_model_for :product
+ assert_generated_fixtures_for :products
+ assert_generated_functional_test_for :products
+ assert_generated_helper_for :products
+ assert_generated_migration :create_products
+ assert_added_route_for :products
+ end
+
+ def test_resource_skip_migration_skips_migration
+ run_generator('resource', %w(Product --skip-migration))
+
+ assert_generated_controller_for :products
+ assert_generated_model_for :product
+ assert_generated_fixtures_for :products
+ assert_generated_functional_test_for :products
+ assert_generated_helper_for :products
+ assert_skipped_migration :create_products
+ assert_added_route_for :products
+ end
+
+end
diff --git a/vendor/rails-2.0.2/railties/test/generators/rails_scaffold_generator_test.rb b/vendor/rails-2.0.2/railties/test/generators/rails_scaffold_generator_test.rb
new file mode 100644
index 000000000..16588affa
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/test/generators/rails_scaffold_generator_test.rb
@@ -0,0 +1,185 @@
+require 'test/unit'
+
+# Optionally load RubyGems.
+begin
+ require 'rubygems'
+rescue LoadError
+end
+
+# Mock out what we need from AR::Base.
+module ActiveRecord
+ class Base
+ class << self
+ attr_accessor :pluralize_table_names
+ end
+ self.pluralize_table_names = true
+ end
+
+ module ConnectionAdapters
+ class Column
+ attr_reader :name, :default, :type, :limit, :null, :sql_type, :precision, :scale
+
+ def initialize(name, default, sql_type = nil)
+ @name=name
+ @default=default
+ @type=@sql_type=sql_type
+ end
+
+ def human_name
+ @name.humanize
+ end
+ end
+ end
+end
+
+# And what we need from ActionView
+module ActionView
+ module Helpers
+ module ActiveRecordHelper; end
+ class InstanceTag; end
+ end
+end
+
+
+# Must set before requiring generator libs.
+tmp_dir="#{File.dirname(__FILE__)}/../fixtures/tmp"
+if defined?(RAILS_ROOT)
+ RAILS_ROOT.replace(tmp_dir)
+else
+ RAILS_ROOT=tmp_dir
+end
+Dir.mkdir(RAILS_ROOT) unless File.exist?(RAILS_ROOT)
+
+$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../../lib"
+require 'rails_generator'
+require "#{File.dirname(__FILE__)}/generator_test_helper"
+
+class RailsScaffoldGeneratorTest < Test::Unit::TestCase
+
+ include GeneratorTestHelper
+
+ def setup
+ ActiveRecord::Base.pluralize_table_names = true
+ Dir.mkdir("#{RAILS_ROOT}/app") unless File.exist?("#{RAILS_ROOT}/app")
+ Dir.mkdir("#{RAILS_ROOT}/app/views") unless File.exist?("#{RAILS_ROOT}/app/views")
+ Dir.mkdir("#{RAILS_ROOT}/app/views/layouts") unless File.exist?("#{RAILS_ROOT}/app/views/layouts")
+ Dir.mkdir("#{RAILS_ROOT}/config") unless File.exist?("#{RAILS_ROOT}/config")
+ Dir.mkdir("#{RAILS_ROOT}/db") unless File.exist?("#{RAILS_ROOT}/db")
+ Dir.mkdir("#{RAILS_ROOT}/test") unless File.exist?("#{RAILS_ROOT}/test")
+ Dir.mkdir("#{RAILS_ROOT}/test/fixtures") unless File.exist?("#{RAILS_ROOT}/test/fixtures")
+ Dir.mkdir("#{RAILS_ROOT}/public") unless File.exist?("#{RAILS_ROOT}/public")
+ Dir.mkdir("#{RAILS_ROOT}/public/stylesheets") unless File.exist?("#{RAILS_ROOT}/public/stylesheets")
+ File.open("#{RAILS_ROOT}/config/routes.rb", 'w') do |f|
+ f<<"ActionController::Routing::Routes.draw do |map|\n\nend\n"
+ end
+ end
+
+ def teardown
+ FileUtils.rm_rf "#{RAILS_ROOT}/app"
+ FileUtils.rm_rf "#{RAILS_ROOT}/test"
+ FileUtils.rm_rf "#{RAILS_ROOT}/config"
+ FileUtils.rm_rf "#{RAILS_ROOT}/db"
+ FileUtils.rm_rf "#{RAILS_ROOT}/public"
+ end
+
+ def test_scaffolded_names
+ g = Rails::Generator::Base.instance('scaffold', %w(ProductLine))
+ assert_equal "ProductLines", g.controller_name
+ assert_equal "ProductLines", g.controller_class_name
+ assert_equal "ProductLine", g.controller_singular_name
+ assert_equal "product_lines", g.controller_plural_name
+ assert_equal "product_lines", g.controller_file_name
+ assert_equal "product_lines", g.controller_table_name
+ end
+
+ def test_scaffold_generates_resources
+
+ run_generator('scaffold', %w(Product))
+
+ assert_generated_controller_for :products do |f|
+
+ assert_has_method f, :index do |name, m|
+ assert_match /@products = Product\.find\(:all\)/, m, "#{name} should query products table"
+ end
+
+ assert_has_method f, :show, :edit, :update, :destroy do |name, m|
+ assert_match /@product = Product\.find\(params\[:id\]\)/, m, "#{name.to_s} should query products table"
+ end
+
+ assert_has_method f, :new do |name, m|
+ assert_match /@product = Product\.new/, m, "#{name.to_s} should instantiate a product"
+ end
+
+ assert_has_method f, :create do |name, m|
+ assert_match /@product = Product\.new\(params\[:product\]\)/, m, "#{name.to_s} should instantiate a product"
+ assert_match /format.xml \{ render :xml => @product.errors, :status => :unprocessable_entity \}/, m, "#{name.to_s} should set status to :unprocessable_entity code for xml"
+ end
+
+ end
+
+ assert_generated_model_for :product
+ assert_generated_functional_test_for :products
+ assert_generated_unit_test_for :product
+ assert_generated_fixtures_for :products
+ assert_generated_helper_for :products
+ assert_generated_stylesheet :scaffold
+ assert_generated_views_for :products, "index.html.erb", "new.html.erb", "edit.html.erb", "show.html.erb"
+ assert_generated_migration :create_products
+ assert_added_route_for :products
+ end
+
+ def test_scaffold_skip_migration_skips_migration
+ run_generator('scaffold', %w(Product --skip-migration))
+
+ assert_generated_model_for :product
+ assert_generated_functional_test_for :products
+ assert_generated_unit_test_for :product
+ assert_generated_fixtures_for :products
+ assert_generated_helper_for :products
+ assert_generated_stylesheet :scaffold
+ assert_generated_views_for :products, "index.html.erb","new.html.erb","edit.html.erb","show.html.erb"
+ assert_skipped_migration :create_products
+ assert_added_route_for :products
+ end
+
+ def test_scaffold_generates_resources_with_attributes
+ run_generator('scaffold', %w(Product name:string supplier_id:integer created_at:timestamp))
+
+ assert_generated_controller_for :products do |f|
+
+ assert_has_method f, :index do |name, m|
+ assert_match /@products = Product\.find\(:all\)/, m, "#{name} should query products table"
+ end
+
+ assert_has_method f, :show, :edit, :update, :destroy do |name, m|
+ assert_match /@product = Product\.find\(params\[:id\]\)/, m, "#{name.to_s} should query products table"
+ end
+
+ assert_has_method f, :new do |name, m|
+ assert_match /@product = Product\.new/, m, "#{name.to_s} should instantiate a product"
+ end
+
+ assert_has_method f, :create do |name, m|
+ assert_match /@product = Product\.new\(params\[:product\]\)/, m, "#{name.to_s} should instantiate a product"
+ assert_match /format.xml \{ render :xml => @product.errors, :status => :unprocessable_entity \}/, m, "#{name.to_s} should set status to :unprocessable_entity code for xml"
+ end
+
+ end
+
+ assert_generated_model_for :product
+ assert_generated_functional_test_for :products
+ assert_generated_unit_test_for :product
+ assert_generated_fixtures_for :products
+ assert_generated_helper_for :products
+ assert_generated_stylesheet :scaffold
+ assert_generated_views_for :products, "index.html.erb", "new.html.erb", "edit.html.erb", "show.html.erb"
+ assert_generated_migration :create_products do |t|
+ assert_generated_column t, :name, :string
+ assert_generated_column t, :supplier_id, :integer
+ assert_generated_column t, :created_at, :timestamp
+ end
+
+ assert_added_route_for :products
+ end
+
+end
diff --git a/vendor/rails-2.0.2/railties/test/initializer_test.rb b/vendor/rails-2.0.2/railties/test/initializer_test.rb
new file mode 100644
index 000000000..156f670e8
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/test/initializer_test.rb
@@ -0,0 +1,218 @@
+require "#{File.dirname(__FILE__)}/abstract_unit"
+require 'initializer'
+
+class ConfigurationMock < Rails::Configuration
+ attr_reader :environment_path
+
+ def initialize(envpath)
+ super()
+ @environment_path = envpath
+ end
+end
+
+class Initializer_load_environment_Test < Test::Unit::TestCase
+
+ def test_load_environment_with_constant
+ config = ConfigurationMock.new("#{File.dirname(__FILE__)}/fixtures/environment_with_constant.rb")
+ assert_nil $initialize_test_set_from_env
+ Rails::Initializer.run(:load_environment, config)
+ assert_equal "success", $initialize_test_set_from_env
+ ensure
+ $initialize_test_set_from_env = nil
+ end
+
+end
+
+class Initializer_after_initialize_with_blocks_environment_Test < Test::Unit::TestCase
+ def setup
+ config = ConfigurationMock.new("")
+ config.after_initialize do
+ $test_after_initialize_block1 = "success"
+ end
+ config.after_initialize do
+ $test_after_initialize_block2 = "congratulations"
+ end
+ assert_nil $test_after_initialize_block1
+ assert_nil $test_after_initialize_block2
+
+ Rails::Initializer.run(:after_initialize, config)
+ end
+
+ def teardown
+ $test_after_initialize_block1 = nil
+ $test_after_initialize_block2 = nil
+ end
+
+ def test_should_have_called_the_first_after_initialize_block
+ assert_equal "success", $test_after_initialize_block1
+ end
+
+ def test_should_have_called_the_second_after_initialize_block
+ assert_equal "congratulations", $test_after_initialize_block2
+ end
+end
+
+class Initializer_after_initialize_with_no_block_environment_Test < Test::Unit::TestCase
+
+ def setup
+ config = ConfigurationMock.new("")
+ config.after_initialize do
+ $test_after_initialize_block1 = "success"
+ end
+ config.after_initialize # don't pass a block, this is what we're testing!
+ config.after_initialize do
+ $test_after_initialize_block2 = "congratulations"
+ end
+ assert_nil $test_after_initialize_block1
+
+ Rails::Initializer.run(:after_initialize, config)
+ end
+
+ def teardown
+ $test_after_initialize_block1 = nil
+ $test_after_initialize_block2 = nil
+ end
+
+ def test_should_have_called_the_first_after_initialize_block
+ assert_equal "success", $test_after_initialize_block1, "should still get set"
+ end
+
+ def test_should_have_called_the_second_after_initialize_block
+ assert_equal "congratulations", $test_after_initialize_block2
+ end
+
+end
+
+uses_mocha 'framework paths' do
+ class ConfigurationFrameworkPathsTests < Test::Unit::TestCase
+ def setup
+ @config = Rails::Configuration.new
+ @config.frameworks.clear
+
+ File.stubs(:directory?).returns(true)
+ @config.stubs(:framework_root_path).returns('')
+ end
+
+ def test_minimal
+ expected = %w(
+ /railties
+ /railties/lib
+ /activesupport/lib
+ )
+ assert_equal expected, @config.framework_paths
+ end
+
+ def test_actioncontroller_or_actionview_add_actionpack
+ @config.frameworks << :action_controller
+ assert_framework_path '/actionpack/lib'
+
+ @config.frameworks = [:action_view]
+ assert_framework_path '/actionpack/lib'
+ end
+
+ def test_paths_for_ar_ares_and_mailer
+ [:active_record, :action_mailer, :active_resource, :action_web_service].each do |framework|
+ @config.frameworks = [framework]
+ assert_framework_path "/#{framework.to_s.gsub('_', '')}/lib"
+ end
+ end
+
+ def test_unknown_framework_raises_error
+ @config.frameworks << :action_foo
+ initializer = Rails::Initializer.new @config
+ initializer.expects(:require).raises(LoadError)
+
+ assert_raise RuntimeError do
+ initializer.send :require_frameworks
+ end
+ end
+
+ protected
+
+ def assert_framework_path(path)
+ assert @config.framework_paths.include?(path),
+ "<#{path.inspect}> not found among <#{@config.framework_paths.inspect}>"
+ end
+ end
+end
+
+uses_mocha "Initializer plugin loading tests" do
+ require File.dirname(__FILE__) + '/plugin_test_helper'
+
+ class InitializerPluginLoadingTests < Test::Unit::TestCase
+ def setup
+ @configuration = Rails::Configuration.new
+ @configuration.plugin_paths << plugin_fixture_root_path
+ @initializer = Rails::Initializer.new(@configuration)
+ @valid_plugin_path = plugin_fixture_path('default/stubby')
+ @empty_plugin_path = plugin_fixture_path('default/empty')
+ end
+
+ def test_no_plugins_are_loaded_if_the_configuration_has_an_empty_plugin_list
+ only_load_the_following_plugins! []
+ @initializer.load_plugins
+ assert_equal [], @initializer.loaded_plugins
+ end
+
+ def test_only_the_specified_plugins_are_located_in_the_order_listed
+ plugin_names = [:plugin_with_no_lib_dir, :acts_as_chunky_bacon]
+ only_load_the_following_plugins! plugin_names
+ load_plugins!
+ assert_plugins plugin_names, @initializer.loaded_plugins
+ end
+
+ def test_all_plugins_are_loaded_when_registered_plugin_list_is_untouched
+ failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
+ load_plugins!
+ assert_plugins [:a, :acts_as_chunky_bacon, :plugin_with_no_lib_dir, :stubby], @initializer.loaded_plugins, failure_tip
+ end
+
+ def test_all_plugins_loaded_when_all_is_used
+ plugin_names = [:stubby, :acts_as_chunky_bacon, :all]
+ only_load_the_following_plugins! plugin_names
+ load_plugins!
+ failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
+ assert_plugins [:stubby, :acts_as_chunky_bacon, :a, :plugin_with_no_lib_dir], @initializer.loaded_plugins, failure_tip
+ end
+
+ def test_all_plugins_loaded_after_all
+ plugin_names = [:stubby, :all, :acts_as_chunky_bacon]
+ only_load_the_following_plugins! plugin_names
+ load_plugins!
+ failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
+ assert_plugins [:stubby, :a, :plugin_with_no_lib_dir, :acts_as_chunky_bacon], @initializer.loaded_plugins, failure_tip
+ end
+
+ def test_plugin_names_may_be_strings
+ plugin_names = ['stubby', 'acts_as_chunky_bacon', :a, :plugin_with_no_lib_dir]
+ only_load_the_following_plugins! plugin_names
+ load_plugins!
+ failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
+ assert_plugins plugin_names, @initializer.loaded_plugins, failure_tip
+ end
+
+ def test_registering_a_plugin_name_that_does_not_exist_raises_a_load_error
+ only_load_the_following_plugins! [:stubby, :acts_as_a_non_existant_plugin]
+ assert_raises(LoadError) do
+ load_plugins!
+ end
+ end
+
+ def test_should_ensure_all_loaded_plugins_load_paths_are_added_to_the_load_path
+ only_load_the_following_plugins! [:stubby, :acts_as_chunky_bacon]
+
+ @initializer.add_plugin_load_paths
+
+ assert $LOAD_PATH.include?(File.join(plugin_fixture_path('default/stubby'), 'lib'))
+ assert $LOAD_PATH.include?(File.join(plugin_fixture_path('default/acts/acts_as_chunky_bacon'), 'lib'))
+ end
+
+ private
+
+ def load_plugins!
+ @initializer.add_plugin_load_paths
+ @initializer.load_plugins
+ end
+ end
+
+end
diff --git a/vendor/rails-2.0.2/railties/test/mocks/routes.rb b/vendor/rails-2.0.2/railties/test/mocks/routes.rb
new file mode 100644
index 000000000..ea1286368
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/test/mocks/routes.rb
@@ -0,0 +1,6 @@
+module ActionController
+ module Routing
+ class Routes
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/test/plugin_loader_test.rb b/vendor/rails-2.0.2/railties/test/plugin_loader_test.rb
new file mode 100644
index 000000000..fe77de447
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/test/plugin_loader_test.rb
@@ -0,0 +1,140 @@
+require File.dirname(__FILE__) + '/plugin_test_helper'
+
+uses_mocha "Plugin Loader Tests" do
+
+ class TestPluginLoader < Test::Unit::TestCase
+ ORIGINAL_LOAD_PATH = $LOAD_PATH.dup
+
+ def setup
+ reset_load_path!
+
+ @configuration = Rails::Configuration.new
+ @configuration.plugin_paths << plugin_fixture_root_path
+ @initializer = Rails::Initializer.new(@configuration)
+ @valid_plugin_path = plugin_fixture_path('default/stubby')
+ @empty_plugin_path = plugin_fixture_path('default/empty')
+
+ @loader = Rails::Plugin::Loader.new(@initializer)
+ end
+
+ def test_should_locate_plugins_by_asking_each_locator_specifed_in_configuration_for_its_plugins_result
+ locator_1 = stub(:plugins => [:a, :b, :c])
+ locator_2 = stub(:plugins => [:d, :e, :f])
+ locator_class_1 = stub(:new => locator_1)
+ locator_class_2 = stub(:new => locator_2)
+ @configuration.plugin_locators = [locator_class_1, locator_class_2]
+ assert_equal [:a, :b, :c, :d, :e, :f], @loader.send(:locate_plugins)
+ end
+
+ def test_should_memoize_the_result_of_locate_plugins_as_all_plugins
+ plugin_list = [:a, :b, :c]
+ @loader.expects(:locate_plugins).once.returns(plugin_list)
+ assert_equal plugin_list, @loader.all_plugins
+ assert_equal plugin_list, @loader.all_plugins # ensuring that locate_plugins isn't called again
+ end
+
+ def test_should_return_empty_array_if_configuration_plugins_is_empty
+ @configuration.plugins = []
+ assert_equal [], @loader.plugins
+ end
+
+ def test_should_find_all_availble_plugins_and_return_as_all_plugins
+ failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
+ assert_plugins [:a, :acts_as_chunky_bacon, :plugin_with_no_lib_dir, :stubby], @loader.all_plugins, failure_tip
+ end
+
+ def test_should_return_all_plugins_as_plugins_when_registered_plugin_list_is_untouched
+ failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
+ assert_plugins [:a, :acts_as_chunky_bacon, :plugin_with_no_lib_dir, :stubby], @loader.plugins, failure_tip
+ end
+
+ def test_should_return_all_plugins_as_plugins_when_registered_plugin_list_is_nil
+ @configuration.plugins = nil
+ failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
+ assert_plugins [:a, :acts_as_chunky_bacon, :plugin_with_no_lib_dir, :stubby], @loader.plugins, failure_tip
+ end
+
+ def test_should_return_specific_plugins_named_in_config_plugins_array_if_set
+ plugin_names = [:acts_as_chunky_bacon, :stubby]
+ only_load_the_following_plugins! plugin_names
+ assert_plugins plugin_names, @loader.plugins
+ end
+
+ def test_should_respect_the_order_of_plugins_given_in_configuration
+ plugin_names = [:stubby, :acts_as_chunky_bacon]
+ only_load_the_following_plugins! plugin_names
+ assert_plugins plugin_names, @loader.plugins
+ end
+
+ def test_should_load_all_plugins_in_natural_order_when_all_is_used
+ only_load_the_following_plugins! [:all]
+ failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
+ assert_plugins [:a, :acts_as_chunky_bacon, :plugin_with_no_lib_dir, :stubby], @loader.plugins, failure_tip
+ end
+
+ def test_should_load_specified_plugins_in_order_and_then_all_remaining_plugins_when_all_is_used
+ only_load_the_following_plugins! [:stubby, :acts_as_chunky_bacon, :all]
+ failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
+ assert_plugins [:stubby, :acts_as_chunky_bacon, :a, :plugin_with_no_lib_dir], @loader.plugins, failure_tip
+ end
+
+ def test_should_be_able_to_specify_loading_of_plugins_loaded_after_all
+ only_load_the_following_plugins! [:stubby, :all, :acts_as_chunky_bacon]
+ failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
+ assert_plugins [:stubby, :a, :plugin_with_no_lib_dir, :acts_as_chunky_bacon], @loader.plugins, failure_tip
+ end
+
+ def test_should_accept_plugin_names_given_as_strings
+ only_load_the_following_plugins! ['stubby', 'acts_as_chunky_bacon', :a, :plugin_with_no_lib_dir]
+ failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
+ assert_plugins [:stubby, :acts_as_chunky_bacon, :a, :plugin_with_no_lib_dir], @loader.plugins, failure_tip
+ end
+
+ def test_should_add_plugin_load_paths_to_global_LOAD_PATH_array
+ only_load_the_following_plugins! [:stubby, :acts_as_chunky_bacon]
+ stubbed_application_lib_index_in_LOAD_PATHS = 5
+ @loader.stubs(:application_lib_index).returns(stubbed_application_lib_index_in_LOAD_PATHS)
+
+ @loader.add_plugin_load_paths
+
+ assert $LOAD_PATH.index(File.join(plugin_fixture_path('default/stubby'), 'lib')) >= stubbed_application_lib_index_in_LOAD_PATHS
+ assert $LOAD_PATH.index(File.join(plugin_fixture_path('default/acts/acts_as_chunky_bacon'), 'lib')) >= stubbed_application_lib_index_in_LOAD_PATHS
+ end
+
+ def test_should_add_plugin_load_paths_to_Dependencies_load_paths
+ only_load_the_following_plugins! [:stubby, :acts_as_chunky_bacon]
+
+ @loader.add_plugin_load_paths
+
+ assert Dependencies.load_paths.include?(File.join(plugin_fixture_path('default/stubby'), 'lib'))
+ assert Dependencies.load_paths.include?(File.join(plugin_fixture_path('default/acts/acts_as_chunky_bacon'), 'lib'))
+ end
+
+ def test_should_add_plugin_load_paths_to_Dependencies_load_once_paths
+ only_load_the_following_plugins! [:stubby, :acts_as_chunky_bacon]
+
+ @loader.add_plugin_load_paths
+
+ assert Dependencies.load_once_paths.include?(File.join(plugin_fixture_path('default/stubby'), 'lib'))
+ assert Dependencies.load_once_paths.include?(File.join(plugin_fixture_path('default/acts/acts_as_chunky_bacon'), 'lib'))
+ end
+
+ def test_should_add_all_load_paths_from_a_plugin_to_LOAD_PATH_array
+ plugin_load_paths = ["a", "b"]
+ plugin = stub(:load_paths => plugin_load_paths)
+ @loader.stubs(:plugins).returns([plugin])
+
+ @loader.add_plugin_load_paths
+
+ plugin_load_paths.each { |path| assert $LOAD_PATH.include?(path) }
+ end
+
+ private
+
+ def reset_load_path!
+ $LOAD_PATH.clear
+ ORIGINAL_LOAD_PATH.each { |path| $LOAD_PATH << path }
+ end
+ end
+
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/railties/test/plugin_locator_test.rb b/vendor/rails-2.0.2/railties/test/plugin_locator_test.rb
new file mode 100644
index 000000000..ccd270dd1
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/test/plugin_locator_test.rb
@@ -0,0 +1,69 @@
+require File.dirname(__FILE__) + '/plugin_test_helper'
+
+uses_mocha "Plugin Locator Tests" do
+
+ class PluginLocatorTest < Test::Unit::TestCase
+
+ def test_should_require_subclasses_to_implement_the_plugins_method
+ assert_raises(RuntimeError) do
+ Rails::Plugin::Locator.new(nil).plugins
+ end
+ end
+
+ def test_should_iterator_over_plugins_returned_by_plugins_when_calling_each
+ locator = Rails::Plugin::Locator.new(nil)
+ locator.stubs(:plugins).returns([:a, :b, :c])
+ plugin_consumer = mock
+ plugin_consumer.expects(:consume).with(:a)
+ plugin_consumer.expects(:consume).with(:b)
+ plugin_consumer.expects(:consume).with(:c)
+
+ locator.each do |plugin|
+ plugin_consumer.consume(plugin)
+ end
+ end
+
+ end
+
+
+ class PluginFileSystemLocatorTest < Test::Unit::TestCase
+ def setup
+ @configuration = Rails::Configuration.new
+ # We need to add our testing plugin directory to the plugin paths so
+ # the locator knows where to look for our plugins
+ @configuration.plugin_paths << plugin_fixture_root_path
+ @initializer = Rails::Initializer.new(@configuration)
+ @locator = Rails::Plugin::FileSystemLocator.new(@initializer)
+ @valid_plugin_path = plugin_fixture_path('default/stubby')
+ @empty_plugin_path = plugin_fixture_path('default/empty')
+ end
+
+ def test_should_return_rails_plugin_instances_when_calling_create_plugin_with_a_valid_plugin_directory
+ assert_kind_of Rails::Plugin, @locator.send(:create_plugin, @valid_plugin_path)
+ end
+
+ def test_should_return_nil_when_calling_create_plugin_with_an_invalid_plugin_directory
+ assert_nil @locator.send(:create_plugin, @empty_plugin_path)
+ end
+
+ def test_should_return_all_plugins_found_under_the_set_plugin_paths
+ assert_equal ["a", "acts_as_chunky_bacon", "plugin_with_no_lib_dir", "stubby"], @locator.plugins.map(&:name)
+ end
+
+ def test_should_find_plugins_only_under_the_plugin_paths_set_in_configuration
+ @configuration.plugin_paths = [File.join(plugin_fixture_root_path, "default")]
+ assert_equal ["acts_as_chunky_bacon", "plugin_with_no_lib_dir", "stubby"], @locator.plugins.map(&:name)
+
+ @configuration.plugin_paths = [File.join(plugin_fixture_root_path, "alternate")]
+ assert_equal ["a"], @locator.plugins.map(&:name)
+ end
+
+ def test_should_not_raise_any_error_and_return_no_plugins_if_the_plugin_path_value_does_not_exist
+ @configuration.plugin_paths = ["some_missing_directory"]
+ assert_nothing_raised do
+ assert @locator.plugins.empty?
+ end
+ end
+ end
+
+end # uses_mocha \ No newline at end of file
diff --git a/vendor/rails-2.0.2/railties/test/plugin_test.rb b/vendor/rails-2.0.2/railties/test/plugin_test.rb
new file mode 100644
index 000000000..0f08c314d
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/test/plugin_test.rb
@@ -0,0 +1,141 @@
+require File.dirname(__FILE__) + '/plugin_test_helper'
+
+uses_mocha "Plugin Tests" do
+
+ class PluginTest < Test::Unit::TestCase
+
+ def setup
+ @initializer = Rails::Initializer.new(Rails::Configuration.new)
+ @valid_plugin_path = plugin_fixture_path('default/stubby')
+ @empty_plugin_path = plugin_fixture_path('default/empty')
+ end
+
+ def test_should_determine_plugin_name_from_the_directory_of_the_plugin
+ assert_equal 'stubby', plugin_for(@valid_plugin_path).name
+ assert_equal 'empty', plugin_for(@empty_plugin_path).name
+ end
+
+ def test_should_not_be_loaded_when_created
+ assert !plugin_for(@valid_plugin_path).loaded?
+ end
+
+ def test_should_be_marked_as_loaded_when_load_is_called
+ plugin = plugin_for(@valid_plugin_path)
+ assert !plugin.loaded?
+ plugin.stubs(:evaluate_init_rb)
+ assert_nothing_raised do
+ plugin.send(:load, anything)
+ end
+ assert plugin.loaded?
+ end
+
+ def test_should_determine_validity_of_given_path
+ # This is a plugin path, with a lib dir
+ assert plugin_for(@valid_plugin_path).valid?
+ # This just has an init.rb and no lib dir
+ assert plugin_for(plugin_fixture_path('default/plugin_with_no_lib_dir')).valid?
+ # This would be a plugin path, but the directory is empty
+ assert !plugin_for(plugin_fixture_path('default/empty')).valid?
+ # This is a non sense path
+ assert !plugin_for(plugin_fixture_path('default/this_directory_does_not_exist')).valid?
+ end
+
+ def test_should_return_empty_array_for_load_paths_when_plugin_has_no_lib_directory
+ assert_equal [], plugin_for(plugin_fixture_path('default/plugin_with_no_lib_dir')).load_paths
+ end
+
+ def test_should_return_array_with_lib_path_for_load_paths_when_plugin_has_a_lib_directory
+ expected_lib_dir = File.join(plugin_fixture_path('default/stubby'), 'lib')
+ assert_equal [expected_lib_dir], plugin_for(plugin_fixture_path('default/stubby')).load_paths
+ end
+
+ def test_should_raise_a_load_error_when_trying_to_determine_the_load_paths_from_an_invalid_plugin
+ assert_nothing_raised do
+ plugin_for(@valid_plugin_path).load_paths
+ end
+
+ assert_raises(LoadError) do
+ plugin_for(@empty_plugin_path).load_paths
+ end
+
+ assert_raises(LoadError) do
+ plugin_for('this_is_not_a_plugin_directory').load_paths
+ end
+ end
+
+ def test_should_raise_a_load_error_when_trying_to_load_an_invalid_plugin
+ # This path is fine so nothing is raised
+ assert_nothing_raised do
+ plugin = plugin_for(@valid_plugin_path)
+ plugin.stubs(:evaluate_init_rb)
+ plugin.send(:load, @initializer)
+ end
+
+ # This is an empty path so it raises
+ assert_raises(LoadError) do
+ plugin = plugin_for(@empty_plugin_path)
+ plugin.stubs(:evaluate_init_rb)
+ plugin.send(:load, @initializer)
+ end
+
+ assert_raises(LoadError) do
+ plugin = plugin_for('this_is_not_a_plugin_directory')
+ plugin.stubs(:evaluate_init_rb)
+ plugin.send(:load, @initializer)
+ end
+ end
+
+ def test_should_raise_a_load_error_when_trying_to_access_load_paths_of_an_invalid_plugin
+ # This path is fine so nothing is raised
+ assert_nothing_raised do
+ plugin_for(@valid_plugin_path).load_paths
+ end
+
+ # This is an empty path so it raises
+ assert_raises(LoadError) do
+ plugin_for(@empty_plugin_path).load_paths
+ end
+
+ assert_raises(LoadError) do
+ plugin_for('this_is_not_a_plugin_directory').load_paths
+ end
+ end
+
+ def test_loading_a_plugin_gives_the_init_file_access_to_all_it_needs
+ failure_tip = "Perhaps someone has written another test that loads this same plugin and therefore makes the StubbyMixin constant defined already."
+ assert !defined?(StubbyMixin), failure_tip
+ plugin = plugin_for(@valid_plugin_path)
+ plugin.load_paths.each { |path| $LOAD_PATH.unshift(path) }
+ # The init.rb of this plugin raises if it doesn't have access to all the things it needs
+ assert_nothing_raised do
+ plugin.load(@initializer)
+ end
+ assert defined?(StubbyMixin)
+ end
+
+ def test_should_sort_naturally_by_name
+ a = plugin_for("path/a")
+ b = plugin_for("path/b")
+ z = plugin_for("path/z")
+ assert_equal [a, b, z], [b, z, a].sort
+ end
+
+ def test_should_only_be_loaded_once
+ plugin = plugin_for(@valid_plugin_path)
+ assert !plugin.loaded?
+ plugin.expects(:evaluate_init_rb)
+ assert_nothing_raised do
+ plugin.send(:load, @initializer)
+ plugin.send(:load, @initializer)
+ end
+ assert plugin.loaded?
+ end
+
+ private
+
+ def plugin_for(path)
+ Rails::Plugin.new(path)
+ end
+ end
+
+end # uses_mocha \ No newline at end of file
diff --git a/vendor/rails-2.0.2/railties/test/plugin_test_helper.rb b/vendor/rails-2.0.2/railties/test/plugin_test_helper.rb
new file mode 100644
index 000000000..f8c094d19
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/test/plugin_test_helper.rb
@@ -0,0 +1,29 @@
+$:.unshift File.dirname(__FILE__) + "/../lib"
+$:.unshift File.dirname(__FILE__) + "/../../activesupport/lib"
+
+require 'test/unit'
+require 'active_support'
+require 'initializer'
+require File.join(File.dirname(__FILE__), 'abstract_unit')
+
+# We need to set RAILS_ROOT if it isn't already set
+RAILS_ROOT = '.' unless defined?(RAILS_ROOT)
+
+class Test::Unit::TestCase
+ private
+ def plugin_fixture_root_path
+ File.join(File.dirname(__FILE__), 'fixtures', 'plugins')
+ end
+
+ def only_load_the_following_plugins!(plugins)
+ @initializer.configuration.plugins = plugins
+ end
+
+ def plugin_fixture_path(path)
+ File.join(plugin_fixture_root_path, path)
+ end
+
+ def assert_plugins(list_of_names, array_of_plugins, message=nil)
+ assert_equal list_of_names.map(&:to_s), array_of_plugins.map(&:name), message
+ end
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/railties/test/rails_generator_test.rb b/vendor/rails-2.0.2/railties/test/rails_generator_test.rb
new file mode 100644
index 000000000..51d02312b
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/test/rails_generator_test.rb
@@ -0,0 +1,137 @@
+require 'test/unit'
+
+# Optionally load RubyGems.
+begin
+ require 'rubygems'
+rescue LoadError
+end
+
+# Mock out what we need from AR::Base.
+module ActiveRecord
+ class Base
+ class << self
+ attr_accessor :pluralize_table_names
+ end
+ self.pluralize_table_names = true
+ end
+end
+
+# And what we need from ActionView
+module ActionView
+ module Helpers
+ module ActiveRecordHelper; end
+ class InstanceTag; end
+ end
+end
+
+
+# Must set before requiring generator libs.
+if defined?(RAILS_ROOT)
+ RAILS_ROOT.replace "#{File.dirname(__FILE__)}/fixtures"
+else
+ RAILS_ROOT = "#{File.dirname(__FILE__)}/fixtures"
+end
+
+$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
+require 'rails_generator'
+
+
+class RailsGeneratorTest < Test::Unit::TestCase
+ BUILTINS = %w(controller integration_test mailer migration model observer plugin resource scaffold session_migration)
+ CAPITALIZED_BUILTINS = BUILTINS.map { |b| b.capitalize }
+
+ def setup
+ ActiveRecord::Base.pluralize_table_names = true
+ end
+
+ def test_sources
+ expected = [:lib, :vendor,
+ :plugins, :plugins, # <plugin>/generators and <plugin>/rails_generators
+ :user,
+ :RubyGems, :RubyGems, # gems named <x>_generator, gems containing /rails_generator/ folder
+ :builtin]
+ expected.delete(:RubyGems) unless Object.const_defined?(:Gem)
+ assert_equal expected, Rails::Generator::Base.sources.map { |s| s.label }
+ end
+
+ def test_lookup_builtins
+ (BUILTINS + CAPITALIZED_BUILTINS).each do |name|
+ assert_nothing_raised do
+ spec = Rails::Generator::Base.lookup(name)
+ assert_not_nil spec
+ assert_kind_of Rails::Generator::Spec, spec
+
+ klass = spec.klass
+ assert klass < Rails::Generator::Base
+ assert_equal spec, klass.spec
+ end
+ end
+ end
+
+ def test_autolookup
+ assert_nothing_raised { ControllerGenerator }
+ assert_nothing_raised { ModelGenerator }
+ end
+
+ def test_lookup_missing_generator
+ assert_raise(MissingSourceFile) {
+ Rails::Generator::Base.lookup('missing_generator').klass
+ }
+ end
+
+ def test_lookup_missing_class
+ spec = nil
+ assert_nothing_raised { spec = Rails::Generator::Base.lookup('missing_class') }
+ assert_not_nil spec
+ assert_kind_of Rails::Generator::Spec, spec
+ assert_raise(NameError) { spec.klass }
+ end
+
+ def test_generator_usage
+ (BUILTINS - ["session_migration"]).each do |name|
+ assert_raise(Rails::Generator::UsageError, "Generator '#{name}' should raise an error without arguments") {
+ Rails::Generator::Base.instance(name)
+ }
+ end
+ end
+
+ def test_generator_spec
+ spec = Rails::Generator::Base.lookup('working')
+ assert_equal 'working', spec.name
+ assert_equal "#{RAILS_ROOT}/lib/generators/working", spec.path
+ assert_equal :lib, spec.source
+ assert_nothing_raised { assert_match(/WorkingGenerator$/, spec.klass.name) }
+ end
+
+ def test_named_generator_attributes
+ g = Rails::Generator::Base.instance('working', %w(admin/foo bar baz))
+ assert_equal 'admin/foo', g.name
+ assert_equal %w(admin), g.class_path
+ assert_equal 'Admin', g.class_nesting
+ assert_equal 'Admin::Foo', g.class_name
+ assert_equal 'foo', g.singular_name
+ assert_equal 'foos', g.plural_name
+ assert_equal g.singular_name, g.file_name
+ assert_equal "admin_#{g.plural_name}", g.table_name
+ assert_equal %w(bar baz), g.args
+ end
+
+ def test_named_generator_attributes_without_pluralized
+ ActiveRecord::Base.pluralize_table_names = false
+ g = Rails::Generator::Base.instance('working', %w(admin/foo bar baz))
+ assert_equal "admin_#{g.singular_name}", g.table_name
+ end
+
+ def test_session_migration_generator_with_pluralization
+ g = Rails::Generator::Base.instance('session_migration')
+ assert_equal 'session'.pluralize, g.send(:default_session_table_name)
+ ActiveRecord::Base.pluralize_table_names = false
+ assert_equal 'session', g.send(:default_session_table_name)
+ end
+
+ def test_scaffold_controller_name
+ # Default behaviour is use the model name
+ g = Rails::Generator::Base.instance('scaffold', %w(Product))
+ assert_equal "Products", g.controller_name
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/test/rails_info_controller_test.rb b/vendor/rails-2.0.2/railties/test/rails_info_controller_test.rb
new file mode 100644
index 000000000..b73ce5a09
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/test/rails_info_controller_test.rb
@@ -0,0 +1,48 @@
+require "#{File.dirname(__FILE__)}/abstract_unit"
+require 'action_controller'
+require 'action_controller/test_process'
+
+module Rails; end
+require 'rails/info'
+require 'rails/info_controller'
+
+class Rails::InfoController < ActionController::Base
+ @local_request = false
+ class << self
+ cattr_accessor :local_request
+ end
+
+ # Re-raise errors caught by the controller.
+ def rescue_action(e) raise e end;
+
+protected
+ def local_request?
+ self.class.local_request
+ end
+end
+
+ActionController::Routing::Routes.draw do |map|
+ map.connect ':controller/:action/:id'
+end
+
+class Rails::InfoControllerTest < Test::Unit::TestCase
+ def setup
+ @controller = Rails::InfoController.new
+ @request = ActionController::TestRequest.new
+ @response = ActionController::TestResponse.new
+ end
+
+ def test_rails_info_properties_table_rendered_for_local_request
+ Rails::InfoController.local_request = true
+ get :properties
+ assert_tag :tag => 'table'
+ assert_response :success
+ end
+
+ def test_rails_info_properties_error_rendered_for_non_local_request
+ Rails::InfoController.local_request = false
+ get :properties
+ assert_tag :tag => 'p'
+ assert_response 500
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/test/rails_info_test.rb b/vendor/rails-2.0.2/railties/test/rails_info_test.rb
new file mode 100644
index 000000000..a21204658
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/test/rails_info_test.rb
@@ -0,0 +1,105 @@
+$:.unshift File.dirname(__FILE__) + "/../lib"
+$:.unshift File.dirname(__FILE__) + "/../builtin/rails_info"
+$:.unshift File.dirname(__FILE__) + "/../../activesupport/lib"
+
+require 'test/unit'
+require 'active_support'
+
+unless defined?(Rails) && defined?(Rails::Info)
+ module Rails
+ class Info; end
+ end
+end
+
+class InfoTest < Test::Unit::TestCase
+ def setup
+ Rails.send :remove_const, :Info
+ silence_warnings { load 'rails/info.rb' }
+ end
+
+ def test_edge_rails_revision_not_set_when_svn_info_is_empty
+ Rails::Info.property 'Test that this will not be defined' do
+ Rails::Info.edge_rails_revision ''
+ end
+ assert !property_defined?('Test that this will not be defined')
+ end
+
+ def test_edge_rails_revision_extracted_from_svn_info
+ Rails::Info.property 'Test Edge Rails revision' do
+ Rails::Info.edge_rails_revision <<-EOS
+Path: .
+URL: http://www.rubyonrails.com/svn/rails/trunk
+Repository UUID: 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
+Revision: 2881
+Node Kind: directory
+Schedule: normal
+Last Changed Author: sam
+Last Changed Rev: 2881
+Last Changed Date: 2005-11-04 21:04:41 -0600 (Fri, 04 Nov 2005)
+Properties Last Updated: 2005-10-28 19:30:00 -0500 (Fri, 28 Oct 2005)
+
+EOS
+ end
+
+ assert_property 'Test Edge Rails revision', '2881'
+ end
+
+ def test_property_with_block_swallows_exceptions_and_ignores_property
+ assert_nothing_raised do
+ Rails::Info.module_eval do
+ property('Bogus') {raise}
+ end
+ end
+ assert !property_defined?('Bogus')
+ end
+
+ def test_property_with_string
+ Rails::Info.module_eval do
+ property 'Hello', 'World'
+ end
+ assert_property 'Hello', 'World'
+ end
+
+ def test_property_with_block
+ Rails::Info.module_eval do
+ property('Goodbye') {'World'}
+ end
+ assert_property 'Goodbye', 'World'
+ end
+
+ def test_component_version
+ assert_property 'Active Support version', ActiveSupport::VERSION::STRING
+ end
+
+ def test_components_exist
+ Rails::Info.components.each do |component|
+ dir = File.dirname(__FILE__) + "/../../" + component.gsub('_', '')
+ assert File.directory?(dir), "#{component.classify} does not exist"
+ end
+ end
+
+protected
+ def svn_info=(info)
+ Rails::Info.module_eval do
+ class << self
+ def svn_info
+ info
+ end
+ end
+ end
+ end
+
+ def properties
+ Rails::Info.properties
+ end
+
+ def property_defined?(property_name)
+ properties.names.include? property_name
+ end
+
+ def assert_property(property_name, value)
+ raise "Property #{property_name.inspect} not defined" unless
+ property_defined? property_name
+ assert_equal value, properties.value_for(property_name)
+ end
+end
diff --git a/vendor/rails-2.0.2/railties/test/secret_key_generation_test.rb b/vendor/rails-2.0.2/railties/test/secret_key_generation_test.rb
new file mode 100644
index 000000000..093436889
--- /dev/null
+++ b/vendor/rails-2.0.2/railties/test/secret_key_generation_test.rb
@@ -0,0 +1,35 @@
+require 'test/unit'
+
+# Must set before requiring generator libs.
+if defined?(RAILS_ROOT)
+ RAILS_ROOT.replace "#{File.dirname(__FILE__)}/fixtures"
+else
+ RAILS_ROOT = "#{File.dirname(__FILE__)}/fixtures"
+end
+
+$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
+
+require 'rails_generator'
+require 'rails_generator/secret_key_generator'
+require 'rails_generator/generators/applications/app/app_generator'
+
+class SecretKeyGenerationTest < Test::Unit::TestCase
+ SECRET_KEY_MIN_LENGTH = 128
+ APP_NAME = "foo"
+
+ def setup
+ @generator = Rails::SecretKeyGenerator.new(APP_NAME)
+ end
+
+ def test_secret_key_generation
+ assert @generator.generate_secret.length >= SECRET_KEY_MIN_LENGTH
+ end
+
+ Rails::SecretKeyGenerator::GENERATORS.each do |generator|
+ if Rails::SecretKeyGenerator.send("supports_#{generator}?")
+ define_method("test_secret_key_generation_with_#{generator}") do
+ assert @generator.send("generate_secret_with_#{generator}").length >= SECRET_KEY_MIN_LENGTH
+ end
+ end
+ end
+end