Repository: openid/ruby-openid Branch: master Commit: 13a88ad64421 Files: 226 Total size: 1.3 MB Directory structure: gitextract_dyyu04vx/ ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── CHANGES-2.0.0 ├── CHANGES-2.1.0 ├── Gemfile ├── INSTALL.md ├── LICENSE ├── NOTICE ├── README.md ├── Rakefile ├── UPGRADE.md ├── admin/ │ ├── build-docs │ ├── fixperms │ ├── gettlds.py │ ├── graph-require.sh │ ├── library-name │ ├── mkassoc │ ├── prepare-release │ └── runtests ├── examples/ │ ├── README.md │ ├── active_record_openid_store/ │ │ ├── README │ │ ├── XXX_add_open_id_store_to_db.rb │ │ ├── XXX_upgrade_open_id_store.rb │ │ ├── init.rb │ │ ├── lib/ │ │ │ ├── association.rb │ │ │ ├── nonce.rb │ │ │ ├── open_id_setting.rb │ │ │ └── openid_ar_store.rb │ │ └── test/ │ │ └── store_test.rb │ ├── discover │ └── rails_openid/ │ ├── Gemfile │ ├── README │ ├── README.rdoc │ ├── Rakefile │ ├── app/ │ │ ├── assets/ │ │ │ ├── javascripts/ │ │ │ │ └── application.js │ │ │ └── stylesheets/ │ │ │ └── application.css │ │ ├── controllers/ │ │ │ ├── application_controller.rb │ │ │ ├── consumer_controller.rb │ │ │ ├── login_controller.rb │ │ │ └── server_controller.rb │ │ ├── helpers/ │ │ │ ├── application_helper.rb │ │ │ ├── login_helper.rb │ │ │ └── server_helper.rb │ │ ├── mailers/ │ │ │ └── .gitkeep │ │ ├── models/ │ │ │ └── .gitkeep │ │ └── views/ │ │ ├── consumer/ │ │ │ └── index.html.erb │ │ ├── layouts/ │ │ │ └── server.html.erb │ │ ├── login/ │ │ │ └── index.html.erb │ │ └── server/ │ │ └── decide.html.erb │ ├── config/ │ │ ├── application.rb │ │ ├── boot.rb │ │ ├── database.yml │ │ ├── environment.rb │ │ ├── environments/ │ │ │ ├── development.rb │ │ │ ├── production.rb │ │ │ └── test.rb │ │ ├── initializers/ │ │ │ ├── backtrace_silencers.rb │ │ │ ├── inflections.rb │ │ │ ├── mime_types.rb │ │ │ ├── rails_root.rb │ │ │ ├── secret_token.rb │ │ │ ├── session_store.rb │ │ │ └── wrap_parameters.rb │ │ ├── locales/ │ │ │ └── en.yml │ │ └── routes.rb │ ├── config.ru │ ├── db/ │ │ ├── development.sqlite3 │ │ └── seeds.rb │ ├── lib/ │ │ ├── assets/ │ │ │ └── .gitkeep │ │ └── tasks/ │ │ └── .gitkeep │ ├── log/ │ │ ├── .gitkeep │ │ └── development.log │ ├── public/ │ │ ├── 404.html │ │ ├── 422.html │ │ ├── 500.html │ │ ├── dispatch.cgi │ │ ├── dispatch.fcgi │ │ ├── dispatch.rb │ │ ├── javascripts/ │ │ │ ├── application.js │ │ │ ├── controls.js │ │ │ ├── dragdrop.js │ │ │ ├── effects.js │ │ │ └── prototype.js │ │ └── robots.txt │ ├── script/ │ │ └── rails │ └── test/ │ ├── fixtures/ │ │ └── .gitkeep │ ├── functional/ │ │ ├── .gitkeep │ │ ├── login_controller_test.rb │ │ └── server_controller_test.rb │ ├── integration/ │ │ └── .gitkeep │ ├── performance/ │ │ └── browsing_test.rb │ ├── test_helper.rb │ └── unit/ │ └── .gitkeep ├── lib/ │ ├── hmac/ │ │ ├── hmac.rb │ │ ├── sha1.rb │ │ └── sha2.rb │ ├── openid/ │ │ ├── association.rb │ │ ├── consumer/ │ │ │ ├── associationmanager.rb │ │ │ ├── checkid_request.rb │ │ │ ├── discovery.rb │ │ │ ├── discovery_manager.rb │ │ │ ├── html_parse.rb │ │ │ ├── idres.rb │ │ │ ├── responses.rb │ │ │ └── session.rb │ │ ├── consumer.rb │ │ ├── cryptutil.rb │ │ ├── dh.rb │ │ ├── extension.rb │ │ ├── extensions/ │ │ │ ├── ax.rb │ │ │ ├── oauth.rb │ │ │ ├── pape.rb │ │ │ ├── sreg.rb │ │ │ └── ui.rb │ │ ├── fetchers.rb │ │ ├── kvform.rb │ │ ├── kvpost.rb │ │ ├── message.rb │ │ ├── protocolerror.rb │ │ ├── server.rb │ │ ├── store/ │ │ │ ├── filesystem.rb │ │ │ ├── interface.rb │ │ │ ├── memcache.rb │ │ │ ├── memory.rb │ │ │ └── nonce.rb │ │ ├── trustroot.rb │ │ ├── urinorm.rb │ │ ├── util.rb │ │ ├── version.rb │ │ └── yadis/ │ │ ├── accept.rb │ │ ├── constants.rb │ │ ├── discovery.rb │ │ ├── filters.rb │ │ ├── htmltokenizer.rb │ │ ├── parsehtml.rb │ │ ├── services.rb │ │ ├── xrds.rb │ │ ├── xri.rb │ │ └── xrires.rb │ ├── openid.rb │ └── ruby-openid.rb ├── ruby-openid.gemspec ├── setup.rb └── test/ ├── data/ │ ├── accept.txt │ ├── dh.txt │ ├── example-xrds.xml │ ├── linkparse.txt │ ├── n2b64 │ ├── test1-discover.txt │ ├── test1-parsehtml.txt │ ├── test_discover/ │ │ ├── malformed_meta_tag.html │ │ ├── openid.html │ │ ├── openid2.html │ │ ├── openid2_xrds.xml │ │ ├── openid2_xrds_no_local_id.xml │ │ ├── openid_1_and_2.html │ │ ├── openid_1_and_2_xrds.xml │ │ ├── openid_1_and_2_xrds_bad_delegate.xml │ │ ├── openid_and_yadis.html │ │ ├── openid_no_delegate.html │ │ ├── openid_utf8.html │ │ ├── yadis_0entries.xml │ │ ├── yadis_2_bad_local_id.xml │ │ ├── yadis_2entries_delegate.xml │ │ ├── yadis_2entries_idp.xml │ │ ├── yadis_another_delegate.xml │ │ ├── yadis_idp.xml │ │ ├── yadis_idp_delegate.xml │ │ └── yadis_no_delegate.xml │ ├── test_xrds/ │ │ ├── =j3h.2007.11.14.xrds │ │ ├── README │ │ ├── delegated-20060809-r1.xrds │ │ ├── delegated-20060809-r2.xrds │ │ ├── delegated-20060809.xrds │ │ ├── no-xrd.xml │ │ ├── not-xrds.xml │ │ ├── prefixsometimes.xrds │ │ ├── ref.xrds │ │ ├── sometimesprefix.xrds │ │ ├── spoof1.xrds │ │ ├── spoof2.xrds │ │ ├── spoof3.xrds │ │ ├── status222.xrds │ │ ├── subsegments.xrds │ │ └── valid-populated-xrds.xml │ ├── trustroot.txt │ └── urinorm.txt ├── discoverdata.rb ├── test_accept.rb ├── test_association.rb ├── test_associationmanager.rb ├── test_ax.rb ├── test_checkid_request.rb ├── test_consumer.rb ├── test_cryptutil.rb ├── test_dh.rb ├── test_discover.rb ├── test_discovery_manager.rb ├── test_extension.rb ├── test_fetchers.rb ├── test_filters.rb ├── test_idres.rb ├── test_kvform.rb ├── test_kvpost.rb ├── test_linkparse.rb ├── test_message.rb ├── test_nonce.rb ├── test_oauth.rb ├── test_openid_yadis.rb ├── test_pape.rb ├── test_parsehtml.rb ├── test_responses.rb ├── test_server.rb ├── test_sreg.rb ├── test_stores.rb ├── test_trustroot.rb ├── test_ui.rb ├── test_urinorm.rb ├── test_util.rb ├── test_xrds.rb ├── test_xri.rb ├── test_xrires.rb ├── test_yadis_discovery.rb ├── testutil.rb └── util.rb ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ *.gem *.rbc .bundle .config .yardoc Gemfile.lock InstalledFiles _yardoc coverage doc/ lib/bundler/man pkg rdoc spec/reports test/tmp test/version_tmp tmp ================================================ FILE: .travis.yml ================================================ language: ruby sudo: required dist: trusty script: rake rvm: - "1.9" - "2.0" - "2.1" - "2.2" - "2.3" - "2.4" - "2.5" - "2.6" - ruby-head - jruby - jruby-head - jruby-19mode - rubinius-3 before_install: - "gem install bundler || gem install bundler --version '< 2'" matrix: allow_failures: - rvm: "ruby-head" - rvm: "jruby-head" ================================================ FILE: CHANGELOG.md ================================================ # Changelog ## 2.9.2 * Perform all checks before verifying endpoints. [#126](https://github.com/openid/ruby-openid/pull/126) ## 2.9.1 * Updated CHANGELOG.md ## 2.9.0 * Remove deprecated `autorequire` from gemspec. [#123](https://github.com/openid/ruby-openid/pull/123) * Rescue from `Yadis::XRI::XRIHTTPError` on discovery. [#106](https://github.com/openid/ruby-openid/pull/106) * Avoid SSRF for claimed_id request. [#121](https://github.com/openid/ruby-openid/pull/121) * Updated documentation. [#115](https://github.com/openid/ruby-openid/pull/115), [#116](https://github.com/openid/ruby-openid/pull/116), [#117](https://github.com/openid/ruby-openid/pull/117), [#118](https://github.com/openid/ruby-openid/pull/118) * Reduce warnings output in test runs. [#119](https://github.com/openid/ruby-openid/pull/119) * Drop deprecated option from gemspec. [#120](https://github.com/openid/ruby-openid/pull/120) * Remove circular require. [#113](https://github.com/openid/ruby-openid/pull/113) * Updated Travis CI config with Ruby 2.6 [#114](https://github.com/openid/ruby-openid/pull/114) * Simplify Bundler require; remove need for extra `:require`. [#112](https://github.com/openid/ruby-openid/pull/112) ## 2.8.0 * Fix `admin/mkassoc` script. See https://github.com/openid/ruby-openid/pull/103 * Allow specifying timeout for `OpenID::StandardFetcher` in environment variables. See https://github.com/openid/ruby-openid/pull/109 * Fixed some documentation. See https://github.com/openid/ruby-openid/pull/111 * Fixed example server. See https://github.com/openid/ruby-openid/pull/91 * Fixed tests. See https://github.com/openid/ruby-openid/pull/86 * Misc. changes to the CI setup. See - https://github.com/openid/ruby-openid/pull/110 - https://github.com/openid/ruby-openid/pull/108 - https://github.com/openid/ruby-openid/pull/107 ## 2.7.0 * Use RFC 2396 compatible URI parser for trustroot - 7c84ec9ced3ccbdad575e02dbfa81e53b52f909e See https://github.com/openid/ruby-openid/pull/85 * Use HMAC from OpenSSL rather than Digest - ce2e30d7ff3308f17ef7d8c19d6f4752f76c9c40 See https://github.com/openid/ruby-openid/pull/84 * Check if OpenSSL is loaded - 751e55820d958ee781f5abb466a576d83ddde6fd ## 2.6.0 * More safely build filenames - 1c4a90630b183e7572b8ab5f2e3a3e0c0fecd2c7 See https://github.com/openid/ruby-openid/pull/80 * The session serializer of Rails4.1 is json - b44a1eb511dec3be25a07930121bc80cacec0f1c * Handle boolean value to fix signature issue - d65076269b77754da7db6e4b189edeeb9201600d See https://github.com/openid/ruby-openid/pull/76 ## 2.5.0 * Revert json serialization - 8dc60e553369df2300ebb4b83a29618aff643c2c See https://github.com/openid/ruby-openid/pull/73 ## 2.4.0 * Allow expecting a parameter to be nil during return_to verification - 708e992ab3e6c26d478283fc11faa6a0a74bfec0 * Serialize to objects that can be stored as json - db1d8f7b171a333dec4e861fe0fa53ac1d98b188 * Fixed missing XRDS HTTP header in sample provider - dc15fa07fd59fdcf46d659cce34c6ef7a6768fde ## 2.3.0 * Deprecated Ruby 1.8 support - 0694bebc83de0313cfef73a5d0ffd9a293ae71a0 * Fixed encoding errors in test suite - 7ac8e3978f9c733bd5ee8d6b742b515b5427ded2 * Be aware when using Hash or Array as default value for unknown Hash keys - #58 * Stop overwriting String#starts_with? and String#ends_with? if defined - #55 * Ignore Associations For OpenID2 (Google's Security Bug Fix) - #53 * Change "oauth" to "ui" in variable name in the UI extension - #52 * Eliminating runtime warnings - #50 #56 * Upgrade example Rails provider/consumer app to Rails 3 - #49 ## 2.2.3 * Fixed 'invalid byte sequence in UTF-8' error in parse_link_attrs - 0f46921a97677b83b106366c805063105c5e9f20 * Fixed license information in gemspec - f032e949e1ca9078ab7508d9629398ca2c36980a * Update starts/ends_with? to handle nil prefix - beee5e8d1dc24ad55725cfcc720eefba6bdbd279 ## 2.2.2 * Limit fetching file size & disable XML entity expansion - be2bab5c21f04735045e071411b349afb790078f Avoid DoS attack to RPs using large XRDS / too many XML entity expansion in XRDS. ## 2.2.1 * Make bundle exec rake work - 2100f281172427d1557ebe76afbd24072a22d04f * State license in gemspec for automated tools / rubygems.org page - 2d5c3cd8f2476b28d60609822120c79d71919b7b * Use default-external encoding instead of ascii for badly encoded pages - a68d2591ac350459c874da10108e6ff5a8c08750 * Colorize output and reveal tests that never ran - 4b0143f0a3b10060d5f52346954219bba3375039 ## 2.2.0 * Bundler compatibility and bundler gem tasks - 72d551945f9577bf5d0e516c673c648791b0e795 * register_namespace_alias for AX message - aeaf050d21aeb681a220758f1cc61b9086f73152 * Fixed JRuby (1.9 mode) incompatibilty - 40baed6cf7326025058a131c2b76047345618539 * Added UI extension support - a276a63d68639e985c1f327cf817489ccc5f9a17 * Add attr_reader for setup_url on SetupNeededResponse - 75a7e98005542ede6db3fc7f1fc551e0a2ca044a * Encode form inputs - c9e9b5b52f8a23df3159c2387b6330d5df40f35b * Fixed cleanup AR associations whose expiry is past, not upcoming - 2265179a6d5c8b51ccc741180db46b618dd3caf9 * Fixed issue with Memcache store and Dalli - ef84bf73da9c99c67b0632252bf0349e2360cbc7 * Improvements to ActiveRecordStore's gc rake task - 847e19bf60a6b8163c1e0d2e96dbd805c64e2880 ================================================ FILE: CHANGES-2.0.0 ================================================ * API Changes * PAPE (Provider Authentication Policy Extension) module * Updated extension for specification draft 2 * PAPE::Request::from_success_response returns nil if PAPE response arguments were not signed * Added functions to generate request/response HTML forms with auto-submission javascript * Consumer (relying party) API: Auth_OpenID_AuthRequest::htmlMarkup * Server API: Auth_OpenID_OpenIDResponse::toHTML * Removed Rails login generator * SReg::Response::from_success_response returns nil when no signed arguments were found * New Features * Fetchers now only read/request first megabyte of response * Bug fixes * NOT NULL constraints to tables created by ActiveRecordStore * check_authentication requests: copy entire response, not just signed fields. Fixes missing namespace in check_authentication requests * OpenID 1 association requests no longer explicitly set no-encryption session type * Improved HTML parsing * AssociationRequest::answer: include session_type in no-encryption assoc responses * normalize return_to URL before performing return_to verification * OpenID::Consumer::IdResHandler.verify_discovery_results_openid1: fall back to OpenID 1.0 type if 1.1 endpoint cannot be found * StandardFetcher now includes a timeout setting * Handle blank content types in OpenID::Yadis::DiscoveryResult.where_is_yadis? * Properly convert timestamps to ints before storing in DB, and vise versa ================================================ FILE: CHANGES-2.1.0 ================================================ * API Changes * PAPE (Provider Authentication Policy Extension) module * Updated extension for specification draft 2 * PAPE::Request::from_success_response returns nil if PAPE response arguments were not signed * Added functions to generate request/response HTML forms with auto-submission javascript * Consumer (relying party) API: Auth_OpenID_AuthRequest::htmlMarkup * Server API: Auth_OpenID_OpenIDResponse::toHTML * Removed Rails login generator * SReg::Response::from_success_response returns nil when no signed arguments were found * New Features * Fetchers now only read/request first megabyte of response * Bug fixes * NOT NULL constraints to tables created by ActiveRecordStore * check_authentication requests: copy entire response, not just signed fields. Fixes missing namespace in check_authentication requests * OpenID 1 association requests no longer explicitly set no-encryption session type * Improved HTML parsing * AssociationRequest::answer: include session_type in no-encryption assoc responses * normalize return_to URL before performing return_to verification * OpenID::Consumer::IdResHandler.verify_discovery_results_openid1: fall back to OpenID 1.0 type if 1.1 endpoint cannot be found * StandardFetcher now includes a timeout setting * Handle blank content types in OpenID::Yadis::DiscoveryResult.where_is_yadis? * Properly convert timestamps to ints before storing in DB, and vise versa ================================================ FILE: Gemfile ================================================ source 'https://rubygems.org' # Specify your gem's dependencies in ruby-openid.gemspec gemspec gem 'rake' ================================================ FILE: INSTALL.md ================================================ # Ruby OpenID Library Installation ## Install as a gem `ruby-openid` is distributed on [RubyGems](https://rubygems.org/). Install it: gem install ruby-openid This is probably what you need. ## Manual Installation Unpack the archive and run `setup.rb` to install: ruby setup.rb `setup.rb` installs the library into your system ruby. If don't want to add openid to you system ruby, you may instead add the `lib` directory of the extracted tarball to your `RUBYLIB` environment variable: $ export RUBYLIB=${RUBYLIB}:/path/to/ruby-openid/lib ## Testing the Installation Make sure everything installed ok: $> irb irb$> require "openid" => true ## Run the test suite Go into the test directory and execute the `runtests.rb` script. ## Next steps * Run `consumer.rb` in the `examples/` directory. * Get started writing your own consumer using `OpenID::Consumer` * Write your own server with `OpenID::Server` * Use the `OpenIDLoginGenerator`! Read `examples/README.md` for more info. ================================================ FILE: LICENSE ================================================ The code in lib/hmac/ is Copyright 2001 by Daiki Ueno, and distributed under the terms of the Ruby license. See http://www.ruby-lang.org/en/LICENSE.txt lib/openid/yadis/htmltokenizer.rb is Copyright 2004 by Ben Giddings and distributed under the terms of the Ruby license. The remainder of this package is Copyright 2006-2008 by JanRain, Inc. and distributed under the terms of license below: Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: NOTICE ================================================ This product includes software developed by JanRain, available from http://github.com/openid/ruby-openid ================================================ FILE: README.md ================================================ # Ruby OpenID A Ruby library for verifying and serving OpenID identities. [![Build Status](https://secure.travis-ci.org/openid/ruby-openid.svg)](http://travis-ci.org/openid/ruby-openid) ## Features * Easy to use API for verifying OpenID identites - OpenID::Consumer * Support for serving OpenID identites - OpenID::Server * Does not depend on underlying web framework * Supports multiple storage mechanisms (Filesystem, ActiveRecord, Memory) * Example code to help you get started, including: * Ruby on Rails based consumer and server * OpenIDLoginGenerator for quickly getting creating a rails app that uses OpenID for authentication * ActiveRecordOpenIDStore plugin * Comprehensive test suite * Supports both OpenID 1 and OpenID 2 transparently ## Installing Before running the examples or writing your own code you'll need to install the library. See the INSTALL file or use rubygems: gem install ruby-openid Check the installation: $ irb irb> require 'rubygems' => false irb> gem 'ruby-openid' => true The library is known to work with Ruby 1.9.2 and above on Unix, Max OS X and Win32. ## Getting Started The best way to start is to look at the rails_openid example. You can run it with: cd examples/rails_openid script/server If you are writing an OpenID Relying Party, a good place to start is: `examples/rails_openid/app/controllers/consumer_controller.rb` And if you are writing an OpenID provider: `examples/rails_openid/app/controllers/server_controller.rb` The library code is quite well documented, so don't be squeamish, and look at the library itself if there's anything you don't understand in the examples. ## Homepage * GitHub repository: [openid/ruby-openid](http://github.com/openid/ruby-openid) * Homepage: [OpenID.net](http://openid.net/) ## Community Discussion regarding the Ruby OpenID library and other JanRain OpenID libraries takes place on the [OpenID mailing list](http://openid.net/developers/dev-mailing-lists/). Please join this list to discuss, ask implementation questions, report bugs, etc. Also check out the openid channel on the freenode IRC network. If you have a bugfix or feature you'd like to contribute, don't hesitate to send it to us: [How to contribute](http://openidenabled.com/contribute/). ## Author Copyright 2006-2012, JanRain, Inc. Contact openid@janrain.com. ## License Apache Software License. For more information see the LICENSE file. ================================================ FILE: Rakefile ================================================ #!/usr/bin/env rake require 'bundler/gem_tasks' require 'rake/testtask' desc "Run tests" Rake::TestTask.new('test') do |t| t.libs << 'lib' t.libs << 'test' t.test_files = FileList["test/**/test_*.rb"] t.verbose = false end task :default => :test ================================================ FILE: UPGRADE.md ================================================ # Upgrading from the OpenID 1.x series library ## Consumer Upgrade The flow is largely the same, however there are a number of significant changes. The consumer example is helpful to look at: `examples/rails_openid/app/controllers/consumer_controller.rb` ### Stores You will need to require the file for the store that you are using. For the filesystem store, this is 'openid/stores/filesystem' They are also now in modules. The filesystem store is `OpenID::Store::Filesystem` The format has changed, and you should remove your old store directory. The ActiveRecord store (`examples/active_record_openid_store`) still needs to be put in a plugin directory for your rails app. There's a migration that needs to be run; examine the `README` in that directory. Also, note that the stores now can be garbage collected with the method `store.cleanup` ### Starting the OpenID transaction The OpenIDRequest object no longer has status codes. Instead, consumer.begin raises an OpenID::OpenIDError if there is a problem initiating the transaction, so you'll want something along the lines of: begin openid_request = consumer.begin(params[:openid_identifier]) rescue OpenID::OpenIDError => e # display error e return end #success case Data regarding the OpenID server once lived in `openid_request.service` The corresponding object in the 2.0 lib can be retrieved with `openid_request.endpoint` Getting the unverified identifier: Where you once had `openid_request.identity_url` you will now want `openid_request.endpoint.claimed_id` which might be different from what you get at the end of the transaction, since it is now possible for users to enter their server's url directly. Arguments on the return_to URL are now verified, so if you want to add additional arguments to the return_to url, use `openid_request.return_to_args['param'] = value` Generating the redirect is the same as before, but add any extensions first. If you need to set up an SSL certificate authority list for the fetcher, use the 'ca_file' attr_accessor on the `OpenID::StandardFetcher`. This has changed from 'ca_path' in the 1.x.x series library. That is, set `OpenID.fetcher.ca_file = '/path/to/ca.list'` before calling consumer.begin. ### Requesting Simple Registration Data You'll need to require the code for the extension require 'openid/extensions/sreg' The new code for adding an SReg request now looks like: sreg_request = OpenID::SReg::Request.new sreg_request.request_fields(['email', 'dob'], true) # required sreg_request.request_fields(['nickname', 'fullname'], false) # optional sreg_request.policy_url = policy_url openid_request.add_extension(sreg_request) The code for adding other extensions is similar. Code for the Attribute Exchange (AX) and Provider Authentication Policy Extension (PAPE) are included with the library, and additional extensions can be implemented subclassing `OpenID::Extension`. ### Completing the transaction The return_to and its arguments are verified, so you need to pass in the base URL and the arguments. With Rails, the params method mashes together parameters from GET, POST, and the path, so you'll need to pull off the path "parameters" with something like return_to = url_for(:only_path => false, :controller => 'openid', :action => 'complete') parameters = params.reject{|k,v| request.path_parameters[k] } openid_response = consumer.complete(parameters, return_to) The response still uses the status codes, but they are now namespaced slightly differently, for example `OpenID::Consumer::SUCCESS` In the case of failure, the error message is now found in `openid_response.message` The identifier to display to the user can be found in `openid_response.endpoint.display_identifier` The Simple Registration response can be read from the OpenID response with sreg_response = OpenID::SReg::Response.from_success_response(openid_response) nickname = sreg_response['nickname'] # etc. ## Server Upgrade The server code is mostly the same as before, with the exception of extensions. Also, you must pass in the endpoint URL to the server constructor: @server = OpenID::Server.new(store, server_url) I recommend looking at `examples/rails_openid/app/controllers/server_controller.rb` for an example of the new way of doing extensions. -- Dag Arneson, JanRain Inc. Please direct questions to openid@janrain.com ================================================ FILE: admin/build-docs ================================================ #!/usr/bin/env bash # # Build the HTML documentation for the JanRain PHP OpenID library # # Usage: # build-docs # # Must be run from the base of the repository RDOC_FILES="README INSTALL LICENSE UPGRADE lib/openid examples/README" MAIN=README rdoc --main="$MAIN" $RDOC_FILES ================================================ FILE: admin/fixperms ================================================ #!/usr/bin/env bash cat < 60: print output_line + line_suffix output_line = line_prefix + tld else: output_line = new_output_line prefix = separator print output_line + suffix ================================================ FILE: admin/graph-require.sh ================================================ #!/usr/bin/env bash OUTPUT_FILE="deps.png" if [ ! "$1" ] ; then echo "Usage: graph-require.sh [output_filename]" exit 1 fi if [ "$2" ] ; then OUTPUT_FILE=$2 fi grep -r '^ *require ['"'"'"]' $1 > require.txt python < CHANGELOG ================================================ FILE: admin/runtests ================================================ #!/usr/bin/env bash case "$1" in --coverage) shift RUBY="rcov --exclude=^lib/hmac/,^admin/ --sort=coverage" ;; *) RUBY="ruby" ;; esac HERE=$(dirname $(readlink --canonicalize "$0")) REPOROOT=$(dirname "$HERE") TESTING_MEMCACHE="localhost:11211" RUBYLIB="$REPOROOT/lib" $RUBY "$@" "$REPOROOT/admin/runtests.rb" ================================================ FILE: examples/README.md ================================================ This directory contains several examples that demonstrate use of the OpenID library. Make sure you have properly installed the library before running the examples. These examples are a great place to start in integrating OpenID into your application. ## Rails example The `rails_openid` directory contains a fully functional OpenID server and relying party, and acts as a starting point for implementing your own production rails server. You'll need the latest version of Ruby on Rails installed, and then: ```shell cd rails_openid ./script/server ``` Open a web browser to http://localhost:3000/ and follow the instructions. The relevant code to work from when writing your Rails OpenID Relying Party is: rails_openid/app/controllers/consumer_controller.rb If you are working on an OpenID provider, check out rails_openid/app/controllers/server_controller.rb Since the library and examples are Apache-licensed, don't be shy about copy-and-paste. ## Rails ActiveRecord OpenIDStore plugin For various reasons you may want or need to deploy your ruby openid consumer/server using an SQL based store. The `active_record_openid_store` is a plugin that makes using an SQL based store simple. Follow the README inside the plugin's dir for usage. ================================================ FILE: examples/active_record_openid_store/README ================================================ =Active Record OpenID Store Plugin A store is required by an OpenID server and optionally by the consumer to store associations, nonces, and auth key information across requests and processes. If rails is distributed across several machines, they must must all have access to the same OpenID store data, so the FilesystemStore won't do. This directory contains a plugin for connecting your OpenID enabled rails app to an ActiveRecord based OpenID store. ==Install 1) Copy this directory and all it's contents into your RAILS_ROOT/vendor/plugins directory. You structure should look like this: RAILS_ROOT/vendor/plugins/active_record_openid_store/ 2) Copy the migration, XXX_add_open_id_store_to_db.rb to your RAILS_ROOT/db/migrate directory. Rename the XXX portion of the file to next sequential migration number. 3) Run the migration: rake migrate 4) Change your app to use the ActiveRecordOpenIDStore: store = ActiveRecordOpenIDStore.new consumer = OpenID::Consumer.new(session, store) 5) That's it! All your OpenID state will now be stored in the database. ==Upgrade If you are upgrading from the 1.x ActiveRecord store, replace your old RAILS_ROOT/vendor/plugins/active_record_openid_store/ directory with the new one and run the migration XXX_upgrade_open_id_store.rb. ==What about garbage collection? You may garbage collect unused nonces and expired associations using the gc instance method of ActiveRecordOpenIDStore. Hook it up to a task in your app's Rakefile like so: desc 'GC OpenID store, deleting expired nonces and associations' task :gc_openid_store => :environment do require 'openid_ar_store' nonces, associations = ActiveRecordStore.new.cleanup puts "Deleted #{nonces} nonces, #{associations} associations" end Run it by typing: rake gc_openid_store ==Questions? Contact Dag Arneson: dag at janrain dot com ================================================ FILE: examples/active_record_openid_store/XXX_add_open_id_store_to_db.rb ================================================ # Use this migration to create the tables for the ActiveRecord store class AddOpenIdStoreToDb < ActiveRecord::Migration def self.up create_table "open_id_associations", :force => true do |t| t.column "server_url", :string, :null => false t.column "handle", :string, :null => false t.column "secret", :binary, :null => false t.column "issued", :integer, :null => false t.column "lifetime", :integer, :null => false t.column "assoc_type", :string, :null => false end create_table "open_id_nonces", :force => true do |t| t.column :server_url, :string, :null => false t.column :timestamp, :integer, :null => false t.column :salt, :string, :null => false end end def self.down drop_table "open_id_associations" drop_table "open_id_nonces" end end ================================================ FILE: examples/active_record_openid_store/XXX_upgrade_open_id_store.rb ================================================ # Use this migration to upgrade the old 1.1 ActiveRecord store schema # to the new 2.0 schema. class UpgradeOpenIdStore < ActiveRecord::Migration def self.up drop_table "open_id_settings" drop_table "open_id_nonces" create_table "open_id_nonces", :force => true do |t| t.column :server_url, :string, :null => false t.column :timestamp, :integer, :null => false t.column :salt, :string, :null => false end end def self.down drop_table "open_id_nonces" create_table "open_id_nonces", :force => true do |t| t.column "nonce", :string t.column "created", :integer end create_table "open_id_settings", :force => true do |t| t.column "setting", :string t.column "value", :binary end end end ================================================ FILE: examples/active_record_openid_store/init.rb ================================================ # might using the ruby-openid gem begin require 'rubygems' rescue LoadError nil end require 'openid' require 'openid_ar_store' ================================================ FILE: examples/active_record_openid_store/lib/association.rb ================================================ require 'openid/association' require 'time' class Association < ActiveRecord::Base set_table_name 'open_id_associations' def from_record OpenID::Association.new(handle, secret, Time.at(issued), lifetime, assoc_type) end end ================================================ FILE: examples/active_record_openid_store/lib/nonce.rb ================================================ class Nonce < ActiveRecord::Base set_table_name 'open_id_nonces' end ================================================ FILE: examples/active_record_openid_store/lib/open_id_setting.rb ================================================ class OpenIdSetting < ActiveRecord::Base validates_uniqueness_of :setting end ================================================ FILE: examples/active_record_openid_store/lib/openid_ar_store.rb ================================================ require 'association' require 'nonce' require 'openid/store/interface' # not in OpenID module to avoid namespace conflict class ActiveRecordStore < OpenID::Store::Interface def store_association(server_url, assoc) remove_association(server_url, assoc.handle) Association.create!(:server_url => server_url, :handle => assoc.handle, :secret => assoc.secret, :issued => assoc.issued.to_i, :lifetime => assoc.lifetime, :assoc_type => assoc.assoc_type) end def get_association(server_url, handle=nil) assocs = if handle.blank? Association.find_all_by_server_url(server_url) else Association.find_all_by_server_url_and_handle(server_url, handle) end assocs.reverse.each do |assoc| a = assoc.from_record if a.expires_in == 0 assoc.destroy else return a end end if assocs.any? return nil end def remove_association(server_url, handle) Association.delete_all(['server_url = ? AND handle = ?', server_url, handle]) > 0 end def use_nonce(server_url, timestamp, salt) return false if Nonce.find_by_server_url_and_timestamp_and_salt(server_url, timestamp, salt) return false if (timestamp - Time.now.to_i).abs > OpenID::Nonce.skew Nonce.create!(:server_url => server_url, :timestamp => timestamp, :salt => salt) return true end def cleanup_nonces now = Time.now.to_i Nonce.delete_all(["timestamp > ? OR timestamp < ?", now + OpenID::Nonce.skew, now - OpenID::Nonce.skew]) end def cleanup_associations now = Time.now.to_i Association.delete_all(['issued + lifetime < ?',now]) end end ================================================ FILE: examples/active_record_openid_store/test/store_test.rb ================================================ $:.unshift(File.dirname(__FILE__) + '/../lib') require 'test/unit' RAILS_ENV = "test" require File.expand_path(File.join(File.dirname(__FILE__), '../../../../config/environment.rb')) module StoreTestCase @@allowed_handle = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~' @@allowed_nonce = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" def _gen_nonce OpenID::CryptUtil.random_string(8, @@allowed_nonce) end def _gen_handle(n) OpenID::CryptUtil.random_string(n, @@allowed_handle) end def _gen_secret(n, chars=nil) OpenID::CryptUtil.random_string(n, chars) end def _gen_assoc(issued, lifetime=600) secret = _gen_secret(20) handle = _gen_handle(128) OpenID::Association.new(handle, secret, Time.now + issued, lifetime, 'HMAC-SHA1') end def _check_retrieve(url, handle=nil, expected=nil) ret_assoc = @store.get_association(url, handle) if expected.nil? assert_nil(ret_assoc) else assert_equal(expected, ret_assoc) assert_equal(expected.handle, ret_assoc.handle) assert_equal(expected.secret, ret_assoc.secret) end end def _check_remove(url, handle, expected) present = @store.remove_association(url, handle) assert_equal(expected, present) end def test_store server_url = "http://www.myopenid.com/openid" assoc = _gen_assoc(issued=0) # Make sure that a missing association returns no result _check_retrieve(server_url) # Check that after storage, getting returns the same result @store.store_association(server_url, assoc) _check_retrieve(server_url, nil, assoc) # more than once _check_retrieve(server_url, nil, assoc) # Storing more than once has no ill effect @store.store_association(server_url, assoc) _check_retrieve(server_url, nil, assoc) # Removing an association that does not exist returns not present _check_remove(server_url, assoc.handle + 'x', false) # Removing an association that does not exist returns not present _check_remove(server_url + 'x', assoc.handle, false) # Removing an association that is present returns present _check_remove(server_url, assoc.handle, true) # but not present on subsequent calls _check_remove(server_url, assoc.handle, false) # Put assoc back in the store @store.store_association(server_url, assoc) # More recent and expires after assoc assoc2 = _gen_assoc(issued=1) @store.store_association(server_url, assoc2) # After storing an association with a different handle, but the # same server_url, the handle with the later expiration is returned. _check_retrieve(server_url, nil, assoc2) # We can still retrieve the older association _check_retrieve(server_url, assoc.handle, assoc) # Plus we can retrieve the association with the later expiration # explicitly _check_retrieve(server_url, assoc2.handle, assoc2) # More recent, and expires earlier than assoc2 or assoc. Make sure # that we're picking the one with the latest issued date and not # taking into account the expiration. assoc3 = _gen_assoc(issued=2, lifetime=100) @store.store_association(server_url, assoc3) _check_retrieve(server_url, nil, assoc3) _check_retrieve(server_url, assoc.handle, assoc) _check_retrieve(server_url, assoc2.handle, assoc2) _check_retrieve(server_url, assoc3.handle, assoc3) _check_remove(server_url, assoc2.handle, true) _check_retrieve(server_url, nil, assoc3) _check_retrieve(server_url, assoc.handle, assoc) _check_retrieve(server_url, assoc2.handle, nil) _check_retrieve(server_url, assoc3.handle, assoc3) _check_remove(server_url, assoc2.handle, false) _check_remove(server_url, assoc3.handle, true) _check_retrieve(server_url, nil, assoc) _check_retrieve(server_url, assoc.handle, assoc) _check_retrieve(server_url, assoc2.handle, nil) _check_retrieve(server_url, assoc3.handle, nil) _check_remove(server_url, assoc2.handle, false) _check_remove(server_url, assoc.handle, true) _check_remove(server_url, assoc3.handle, false) _check_retrieve(server_url, nil, nil) _check_retrieve(server_url, assoc.handle, nil) _check_retrieve(server_url, assoc2.handle, nil) _check_retrieve(server_url, assoc3.handle, nil) _check_remove(server_url, assoc2.handle, false) _check_remove(server_url, assoc.handle, false) _check_remove(server_url, assoc3.handle, false) assocValid1 = _gen_assoc(-3600, 7200) assocValid2 = _gen_assoc(-5) assocExpired1 = _gen_assoc(-7200, 3600) assocExpired2 = _gen_assoc(-7200, 3600) @store.cleanup_associations @store.store_association(server_url + '1', assocValid1) @store.store_association(server_url + '1', assocExpired1) @store.store_association(server_url + '2', assocExpired2) @store.store_association(server_url + '3', assocValid2) cleaned = @store.cleanup_associations() assert_equal(2, cleaned, "cleaned up associations") end def _check_use_nonce(nonce, expected, server_url, msg='') stamp, salt = OpenID::Nonce::split_nonce(nonce) actual = @store.use_nonce(server_url, stamp, salt) assert_equal(expected, actual, msg) end def test_nonce server_url = "http://www.myopenid.com/openid" [server_url, ''].each{|url| nonce1 = OpenID::Nonce::mk_nonce _check_use_nonce(nonce1, true, url, "#{url}: nonce allowed by default") _check_use_nonce(nonce1, false, url, "#{url}: nonce not allowed twice") _check_use_nonce(nonce1, false, url, "#{url}: nonce not allowed third time") # old nonces shouldn't pass old_nonce = OpenID::Nonce::mk_nonce(3600) _check_use_nonce(old_nonce, false, url, "Old nonce #{old_nonce.inspect} passed") } now = Time.now.to_i old_nonce1 = OpenID::Nonce::mk_nonce(now - 20000) old_nonce2 = OpenID::Nonce::mk_nonce(now - 10000) recent_nonce = OpenID::Nonce::mk_nonce(now - 600) orig_skew = OpenID::Nonce.skew OpenID::Nonce.skew = 0 count = @store.cleanup_nonces OpenID::Nonce.skew = 1000000 ts, salt = OpenID::Nonce::split_nonce(old_nonce1) assert(@store.use_nonce(server_url, ts, salt), "oldnonce1") ts, salt = OpenID::Nonce::split_nonce(old_nonce2) assert(@store.use_nonce(server_url, ts, salt), "oldnonce2") ts, salt = OpenID::Nonce::split_nonce(recent_nonce) assert(@store.use_nonce(server_url, ts, salt), "recent_nonce") OpenID::Nonce.skew = 1000 cleaned = @store.cleanup_nonces assert_equal(2, cleaned, "Cleaned #{cleaned} nonces") OpenID::Nonce.skew = 100000 ts, salt = OpenID::Nonce::split_nonce(old_nonce1) assert(@store.use_nonce(server_url, ts, salt), "oldnonce1 after cleanup") ts, salt = OpenID::Nonce::split_nonce(old_nonce2) assert(@store.use_nonce(server_url, ts, salt), "oldnonce2 after cleanup") ts, salt = OpenID::Nonce::split_nonce(recent_nonce) assert(!@store.use_nonce(server_url, ts, salt), "recent_nonce after cleanup") OpenID::Nonce.skew = orig_skew end end class TestARStore < Test::Unit::TestCase include StoreTestCase def setup @store = ActiveRecordStore.new end end ================================================ FILE: examples/discover ================================================ #!/usr/bin/env ruby require "openid/consumer/discovery" require 'openid/fetchers' OpenID::fetcher_use_env_http_proxy $names = [[:server_url, "Server URL "], [:local_id, "Local ID "], [:canonical_id, "Canonical ID"], ] def show_services(user_input, normalized, services) puts " Claimed identifier: #{normalized}" if services.empty? puts " No OpenID services found" puts else puts " Discovered services:" n = 0 services.each do |service| n += 1 puts " #{n}." $names.each do |meth, name| val = service.send(meth) if val printf(" %s: %s\n", name, val) end end puts " Type URIs:" for type_uri in service.type_uris puts " * #{type_uri}" end puts end end end ARGV.each do |openid_identifier| puts "=" * 50 puts "Running discovery on #{openid_identifier}" begin normalized_identifier, services = OpenID.discover(openid_identifier) rescue OpenID::DiscoveryFailure => why puts "Discovery failed: #{why.message}" puts else show_services(openid_identifier, normalized_identifier, services) end end ================================================ FILE: examples/rails_openid/Gemfile ================================================ source 'https://rubygems.org' gem 'rails', '3.2.13' # Bundle edge Rails instead: # gem 'rails', :git => 'git://github.com/rails/rails.git' gem 'sqlite3' gem 'json' # Gems used only for assets and not required # in production environments by default. group :assets do gem 'sass-rails', '~> 3.2.3' gem 'coffee-rails', '~> 3.2.1' # See https://github.com/sstephenson/execjs#readme for more supported runtimes # gem 'therubyracer', :platforms => :ruby gem 'uglifier', '>= 1.0.3' end gem 'jquery-rails' # To use ActiveModel has_secure_password # gem 'bcrypt-ruby', '~> 3.0.0' # To use Jbuilder templates for JSON # gem 'jbuilder' # Use unicorn as the app server # gem 'unicorn' # Deploy with Capistrano # gem 'capistrano' # To use debugger # gem 'ruby-debug' gem 'ruby-openid', :require => 'openid' ================================================ FILE: examples/rails_openid/README ================================================ == 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. Run the WEBrick servlet: ruby script/server (run with --help for options) ...or if you have lighttpd installed: ruby script/lighttpd (it's faster) 2. Go to http://localhost:3000/ and get "Congratulations, you've put Ruby on Rails!" 3. Follow the guidelines on the "Congratulations, you've put Ruby on Rails!" screen == Example for Apache conf ServerName rails DocumentRoot /path/application/public/ ErrorLog /path/application/log/server.log Options ExecCGI FollowSymLinks AllowOverride all Allow from all Order allow,deny NOTE: Be sure that CGIs can be executed in that directory as well. So ExecCGI should be on and ".cgi" should respond. All requests from 127.0.0.1 go through CGI, so no Apache restart is necessary for changes. All other requests go through FCGI (or mod_ruby), which requires a restart to show changes. == Debugging Rails Have "tail -f" commands running on both the server.log, production.log, and test.log files. 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. == Breakpoints Breakpoint support is available 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 => "[#nil, \"body\"=>nil, \"id\"=>\"1\"}>, #\"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 => #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 == Console You can interact with the domain model by starting the console through script/console. 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 console production. == Description of contents app Holds all the code that's specific to this particular application. app/controllers Holds controllers that should be named like weblog_controller.rb for automated URL mapping. All controllers should descend 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 weblog/index.rhtml for the WeblogController#index action. All views use eRuby syntax. This directory can also be used to keep stylesheets, images, and so on that can be symlinked to public. app/helpers Holds view helpers that should be named like weblog_helper.rb. config Configuration files for the Rails environment, the routing map, the database, and other dependencies. components Self-contained mini-applications that can bundle together controllers, models, and views. 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. script Helper scripts for automation and generation. test Unit and functional tests along with fixtures. vendor External libraries that the application depends on. Also includes the plugins subdirectory. This directory is in the load path. ================================================ FILE: examples/rails_openid/README.rdoc ================================================ == Welcome to Rails Rails is a web-application framework that includes everything needed to create database-backed web applications according to the Model-View-Control pattern. This pattern splits the view (also called the presentation) into "dumb" templates that are primarily responsible for inserting pre-built data in between HTML tags. The model contains the "smart" domain objects (such as Account, Product, Person, Post) that holds all the business logic and knows how to persist themselves to a database. The controller handles the incoming requests (such as Save New Account, Update Product, Show Post) by manipulating the model and directing data to the view. In Rails, the model is handled by what's called an object-relational mapping layer entitled Active Record. This layer allows you to present the data from database rows as objects and embellish these data objects with business logic methods. You can read more about Active Record in link:files/vendor/rails/activerecord/README.html. The controller and view are handled by the Action Pack, which handles both layers by its two parts: Action View and Action Controller. These two layers are bundled in a single package due to their heavy interdependence. This is unlike the relationship between the Active Record and Action Pack that is much more separate. Each of these packages can be used independently outside of Rails. You can read more about Action Pack in link:files/vendor/rails/actionpack/README.html. == Getting Started 1. At the command prompt, create a new Rails application: rails new myapp (where myapp is the application name) 2. Change directory to myapp and start the web server: cd myapp; rails server (run with --help for options) 3. Go to http://localhost:3000/ and you'll see: "Welcome aboard: You're riding Ruby on Rails!" 4. Follow the guidelines to start developing your application. You can find the following resources handy: * The Getting Started Guide: http://guides.rubyonrails.org/getting_started.html * Ruby on Rails Tutorial Book: http://www.railstutorial.org/ == Debugging Rails Sometimes your application goes wrong. Fortunately there are a lot of tools that will help you debug it and get it back on the rails. First area to check is the application log files. Have "tail -f" commands running on the server.log and development.log. Rails will automatically display debugging and runtime information to these files. Debugging info will also be shown in the browser on requests from 127.0.0.1. You can also log your own messages directly into the log file from your code using the Ruby logger class from inside your controllers. Example: class WeblogController < ActionController::Base def destroy @weblog = Weblog.find(params[:id]) @weblog.destroy logger.info("#{Time.now} Destroyed Weblog ID ##{@weblog.id}!") end end The result will be a message in your log file along the lines of: Mon Oct 08 14:22:29 +1000 2007 Destroyed Weblog ID #1! More information on how to use the logger is at http://www.ruby-doc.org/core/ Also, Ruby documentation can be found at http://www.ruby-lang.org/. There are several books available online as well: * Programming Ruby: http://www.ruby-doc.org/docs/ProgrammingRuby/ (Pickaxe) * Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide) These two books will bring you up to speed on the Ruby language and also on programming in general. == Debugger Debugger support is available through the debugger command when you start your Mongrel or WEBrick server with --debugger. This means that you can break out of execution at any point in the code, investigate and change the model, and then, resume execution! You need to install ruby-debug to run the server in debugging mode. With gems, use sudo gem install ruby-debug. Example: class WeblogController < ActionController::Base def index @posts = Post.all debugger end end So the controller will accept the action, run the first line, then present you with a IRB prompt in the server window. Here you can do things like: >> @posts.inspect => "[#nil, "body"=>nil, "id"=>"1"}>, #"Rails", "body"=>"Only ten..", "id"=>"2"}>]" >> @posts.first.title = "hello from a debugger" => "hello from a debugger" ...and even better, you can examine how your runtime objects actually work: >> f = @posts.first => #nil, "body"=>nil, "id"=>"1"}> >> f. Display all 152 possibilities? (y or n) Finally, when you're ready to resume execution, you can enter "cont". == Console The console is a Ruby shell, which allows you to interact with your application's domain model. Here you'll have all parts of the application configured, just like it is when the application is running. You can inspect domain models, change values, and save to the database. Starting the script without arguments will launch it in the development environment. To start the console, run rails console from the application directory. Options: * Passing the -s, --sandbox argument will rollback any modifications made to the database. * Passing an environment name as an argument will load the corresponding environment. Example: rails console production. To reload your controllers and models after launching the console run reload! More information about irb can be found at: link:http://www.rubycentral.org/pickaxe/irb.html == dbconsole You can go to the command line of your database directly through rails dbconsole. You would be connected to the database with the credentials defined in database.yml. Starting the script without arguments will connect you to the development database. Passing an argument will connect you to a different database, like rails dbconsole production. Currently works for MySQL, PostgreSQL and SQLite 3. == Description of Contents The default directory structure of a generated Ruby on Rails application: |-- app | |-- assets | | |-- images | | |-- javascripts | | `-- stylesheets | |-- controllers | |-- helpers | |-- mailers | |-- models | `-- views | `-- layouts |-- config | |-- environments | |-- initializers | `-- locales |-- db |-- doc |-- lib | |-- assets | `-- tasks |-- log |-- public |-- script |-- test | |-- fixtures | |-- functional | |-- integration | |-- performance | `-- unit |-- tmp | `-- cache | `-- assets `-- vendor |-- assets | |-- javascripts | `-- stylesheets `-- plugins app Holds all the code that's specific to this particular application. app/assets Contains subdirectories for images, stylesheets, and JavaScript files. app/controllers Holds controllers that should be named like weblogs_controller.rb for automated URL mapping. All controllers should descend from ApplicationController which itself descends from ActionController::Base. app/models Holds models that should be named like post.rb. Models descend from ActiveRecord::Base by default. app/views Holds the template files for the view that should be named like weblogs/index.html.erb for the WeblogsController#index action. All views use eRuby syntax by default. app/views/layouts Holds the template files for layouts to be used with views. This models the common header/footer method of wrapping views. In your views, define a layout using the layout :default and create a file named default.html.erb. Inside default.html.erb, call <% yield %> to render the view using this layout. app/helpers Holds view helpers that should be named like weblogs_helper.rb. These are generated for you automatically when using generators for controllers. Helpers can be used to wrap functionality for your views into methods. config Configuration files for the Rails environment, the routing map, the database, and other dependencies. db Contains the database schema in schema.rb. db/migrate contains all the sequence of Migrations for your schema. doc This directory is where your application documentation will be stored when generated using rake doc:app lib Application specific libraries. Basically, any kind of custom code that doesn't belong under controllers, models, or helpers. This directory is in the load path. public The directory available for the web server. Also contains the dispatchers and the default HTML files. This should be set as the DOCUMENT_ROOT of your web server. script Helper scripts for automation and generation. test Unit and functional tests along with fixtures. When using the rails generate command, template test files will be generated for you and placed in this directory. vendor External libraries that the application depends on. Also includes the plugins subdirectory. If the app has frozen rails, those gems also go here, under vendor/rails/. This directory is in the load path. ================================================ FILE: examples/rails_openid/Rakefile ================================================ #!/usr/bin/env rake # Add your own tasks in files placed in lib/tasks ending in .rake, # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. require File.expand_path('../config/application', __FILE__) RailsOpenid::Application.load_tasks ================================================ FILE: examples/rails_openid/app/assets/javascripts/application.js ================================================ // This is a manifest file that'll be compiled into application.js, which will include all the files // listed below. // // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. // // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the // the compiled file. // // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD // GO AFTER THE REQUIRES BELOW. // //= require jquery //= require jquery_ujs //= require_tree . ================================================ FILE: examples/rails_openid/app/assets/stylesheets/application.css ================================================ /* * This is a manifest file that'll be compiled into application.css, which will include all the files * listed below. * * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. * * You're free to add application-wide styles to this file and they'll appear at the top of the * compiled file, but it's generally better to create a new file per style scope. * *= require_self *= require_tree . */ ================================================ FILE: examples/rails_openid/app/controllers/application_controller.rb ================================================ class ApplicationController < ActionController::Base protect_from_forgery end ================================================ FILE: examples/rails_openid/app/controllers/consumer_controller.rb ================================================ require 'pathname' require "openid" require 'openid/extensions/sreg' require 'openid/extensions/pape' require 'openid/store/filesystem' class ConsumerController < ApplicationController layout nil def index # render an openid form end def start begin identifier = params[:openid_identifier] if identifier.nil? flash[:error] = "Enter an OpenID identifier" redirect_to :action => 'index' return end oidreq = consumer.begin(identifier) rescue OpenID::OpenIDError => e flash[:error] = "Discovery failed for #{identifier}: #{e}" redirect_to :action => 'index' return end if params[:use_sreg] sregreq = OpenID::SReg::Request.new # required fields sregreq.request_fields(['email','nickname'], true) # optional fields sregreq.request_fields(['dob', 'fullname'], false) oidreq.add_extension(sregreq) oidreq.return_to_args['did_sreg'] = 'y' end if params[:use_pape] papereq = OpenID::PAPE::Request.new papereq.add_policy_uri(OpenID::PAPE::AUTH_PHISHING_RESISTANT) papereq.max_auth_age = 2*60*60 oidreq.add_extension(papereq) oidreq.return_to_args['did_pape'] = 'y' end if params[:force_post] oidreq.return_to_args['force_post']='x'*2048 end return_to = url_for :action => 'complete', :only_path => false realm = url_for :action => 'index', :id => nil, :only_path => false if oidreq.send_redirect?(realm, return_to, params[:immediate]) redirect_to oidreq.redirect_url(realm, return_to, params[:immediate]) else render :text => oidreq.html_markup(realm, return_to, params[:immediate], {'id' => 'openid_form'}) end end def complete # FIXME - url_for some action is not necessarily the current URL. current_url = url_for(:action => 'complete', :only_path => false) parameters = params.reject{|k,v|request.path_parameters[k]} parameters.reject!{|k,v|%w{action controller}.include? k.to_s} oidresp = consumer.complete(parameters, current_url) case oidresp.status when OpenID::Consumer::FAILURE if oidresp.display_identifier flash[:error] = ("Verification of #{oidresp.display_identifier}"\ " failed: #{oidresp.message}") else flash[:error] = "Verification failed: #{oidresp.message}" end when OpenID::Consumer::SUCCESS flash[:success] = ("Verification of #{oidresp.display_identifier}"\ " succeeded.") if params[:did_sreg] sreg_resp = OpenID::SReg::Response.from_success_response(oidresp) sreg_message = "Simple Registration data was requested" if sreg_resp.empty? sreg_message << ", but none was returned." else sreg_message << ". The following data were sent:" sreg_resp.data.each {|k,v| sreg_message << "
#{k}: #{v}" } end flash[:sreg_results] = sreg_message end if params[:did_pape] pape_resp = OpenID::PAPE::Response.from_success_response(oidresp) pape_message = "A phishing resistant authentication method was requested" if pape_resp.auth_policies.member? OpenID::PAPE::AUTH_PHISHING_RESISTANT pape_message << ", and the server reported one." else pape_message << ", but the server did not report one." end if pape_resp.auth_time pape_message << "
Authentication time: #{pape_resp.auth_time} seconds" end if pape_resp.nist_auth_level pape_message << "
NIST Auth Level: #{pape_resp.nist_auth_level}" end flash[:pape_results] = pape_message end when OpenID::Consumer::SETUP_NEEDED flash[:alert] = "Immediate request failed - Setup Needed" when OpenID::Consumer::CANCEL flash[:alert] = "OpenID transaction cancelled." else end redirect_to :action => 'index' end private def consumer if @consumer.nil? dir = Pathname.new(RAILS_ROOT).join('db').join('cstore') store = OpenID::Store::Filesystem.new(dir) @consumer = OpenID::Consumer.new(session, store) end return @consumer end end ================================================ FILE: examples/rails_openid/app/controllers/login_controller.rb ================================================ # Controller for handling the login, logout process for "users" of our # little server. Users have no password. This is just an example. require 'openid' class LoginController < ApplicationController layout 'server' def base_url url_for(:controller => 'login', :action => nil, :only_path => false) end def index response.headers['X-XRDS-Location'] = url_for(:controller => "server", :action => "idp_xrds", :only_path => false) @base_url = base_url # just show the login page end def submit user = params[:username] # if we get a user, log them in by putting their username in # the session hash. unless user.nil? session[:username] = user unless user.nil? session[:approvals] = [] flash[:notice] = "Your OpenID URL is #{base_url}user/#{user}

Proceed to step 2 below." else flash[:error] = "Sorry, couldn't log you in. Try again." end redirect_to :action => 'index' end def logout # delete the username from the session hash session[:username] = nil session[:approvals] = nil redirect_to :action => 'index' end end ================================================ FILE: examples/rails_openid/app/controllers/server_controller.rb ================================================ require 'pathname' require "openid" require "openid/consumer/discovery" require 'openid/extensions/sreg' require 'openid/extensions/pape' require 'openid/store/filesystem' class ServerController < ApplicationController include ServerHelper include OpenID::Server layout nil def index begin oidreq = server.decode_request(params) rescue ProtocolError => e # invalid openid request, so just display a page with an error message render :text => e.to_s, :status => 500 return end # no openid.mode was given unless oidreq render :text => "This is an OpenID server endpoint." return end oidresp = nil if oidreq.kind_of?(CheckIDRequest) identity = oidreq.identity if oidreq.id_select if oidreq.immediate oidresp = oidreq.answer(false) elsif session[:username].nil? # The user hasn't logged in. show_decision_page(oidreq) return else # Else, set the identity to the one the user is using. identity = url_for_user end end if oidresp nil elsif self.is_authorized(identity, oidreq.trust_root) oidresp = oidreq.answer(true, nil, identity) # add the sreg response if requested add_sreg(oidreq, oidresp) # ditto pape add_pape(oidreq, oidresp) elsif oidreq.immediate server_url = url_for :action => 'index' oidresp = oidreq.answer(false, server_url) else show_decision_page(oidreq) return end else oidresp = server.handle_request(oidreq) end self.render_response(oidresp) end def show_decision_page(oidreq, message="Do you trust this site with your identity?") session[:last_oidreq] = oidreq @oidreq = oidreq if message flash[:notice] = message end render :template => 'server/decide', :layout => 'server' end def user_page # Yadis content-negotiation: we want to return the xrds if asked for. accept = request.env['HTTP_ACCEPT'] # This is not technically correct, and should eventually be updated # to do real Accept header parsing and logic. Though I expect it will work # 99% of the time. if accept and accept.include?('application/xrds+xml') user_xrds return end # content negotiation failed, so just render the user page xrds_url = url_for(:controller=>'user',:action=>params[:username])+'/xrds' identity_page = <

OpenID identity page for #{params[:username]}

EOS # Also add the Yadis location header, so that they don't have # to parse the html unless absolutely necessary. response.headers['X-XRDS-Location'] = xrds_url render :text => identity_page end def user_xrds types = [ OpenID::OPENID_2_0_TYPE, OpenID::OPENID_1_0_TYPE, OpenID::SREG_URI, ] render_xrds(types) end def idp_xrds types = [ OpenID::OPENID_IDP_2_0_TYPE, ] render_xrds(types) end def decision oidreq = session[:last_oidreq] session[:last_oidreq] = nil if params[:yes].nil? redirect_to oidreq.cancel_url return else id_to_send = params[:id_to_send] identity = oidreq.identity if oidreq.id_select if id_to_send and id_to_send != "" session[:username] = id_to_send session[:approvals] = [] identity = url_for_user else msg = "You must enter a username to in order to send " + "an identifier to the Relying Party." show_decision_page(oidreq, msg) return end end if session[:approvals] session[:approvals] << oidreq.trust_root else session[:approvals] = [oidreq.trust_root] end oidresp = oidreq.answer(true, nil, identity) add_sreg(oidreq, oidresp) add_pape(oidreq, oidresp) return self.render_response(oidresp) end end protected def server if @server.nil? server_url = url_for :action => 'index', :only_path => false dir = Pathname.new(RAILS_ROOT).join('db').join('openid-store') store = OpenID::Store::Filesystem.new(dir) @server = Server.new(store, server_url) end return @server end def approved(trust_root) return false if session[:approvals].nil? return session[:approvals].member?(trust_root) end def is_authorized(identity_url, trust_root) return (session[:username] and (identity_url == url_for_user) and self.approved(trust_root)) end def render_xrds(types) type_str = "" types.each { |uri| type_str += "#{uri}\n " } yadis = < #{type_str} #{url_for(:controller => 'server', :only_path => false)} EOS render :text => yadis, :content_type => 'application/xrds+xml' end def add_sreg(oidreq, oidresp) # check for Simple Registration arguments and respond sregreq = OpenID::SReg::Request.from_openid_request(oidreq) return if sregreq.nil? # In a real application, this data would be user-specific, # and the user should be asked for permission to release # it. sreg_data = { 'nickname' => session[:username], 'fullname' => 'Mayor McCheese', 'email' => 'mayor@example.com' } sregresp = OpenID::SReg::Response.extract_response(sregreq, sreg_data) oidresp.add_extension(sregresp) end def add_pape(oidreq, oidresp) papereq = OpenID::PAPE::Request.from_openid_request(oidreq) return if papereq.nil? paperesp = OpenID::PAPE::Response.new paperesp.nist_auth_level = 0 # we don't even do auth at all! oidresp.add_extension(paperesp) end def render_response(oidresp) if oidresp.needs_signing signed_response = server.signatory.sign(oidresp) end web_response = server.encode_response(oidresp) case web_response.code when HTTP_OK render :text => web_response.body, :status => 200 when HTTP_REDIRECT redirect_to web_response.headers['location'] else render :text => web_response.body, :status => 400 end end end ================================================ FILE: examples/rails_openid/app/helpers/application_helper.rb ================================================ module ApplicationHelper end ================================================ FILE: examples/rails_openid/app/helpers/login_helper.rb ================================================ module LoginHelper end ================================================ FILE: examples/rails_openid/app/helpers/server_helper.rb ================================================ module ServerHelper def url_for_user url_for :controller => 'user', :action => session[:username] end end ================================================ FILE: examples/rails_openid/app/mailers/.gitkeep ================================================ ================================================ FILE: examples/rails_openid/app/models/.gitkeep ================================================ ================================================ FILE: examples/rails_openid/app/views/consumer/index.html.erb ================================================ Rails OpenID Example Relying Party

Rails OpenID Example Relying Party

<% if flash[:alert] %>
<%= h(flash[:alert]) %>
<% end %> <% if flash[:error] %>
<%= h(flash[:error]) %>
<% end %> <% if flash[:success] %>
<%= h(flash[:success]) %>
<% end %> <% if flash[:sreg_results] %>
<%= flash[:sreg_results] %>
<% end %> <% if flash[:pape_results] %>
<%= flash[:pape_results] %>
<% end %>
'> Identifier:



================================================ FILE: examples/rails_openid/app/views/layouts/server.html.erb ================================================ OpenID Server Example <%#= csrf_meta_tags %> <% if session[:username] %>
Welcome, <%= session[:username] %> | <%= link_to('Log out', :controller => 'login', :action => 'logout') %>
<%= @base_url %>user/<%= session[:username] %>
<% end %>

Ruby OpenID Server Example


<% if flash[:notice] or flash[:error] %>
<%= flash[:error] or flash[:notice] %>
<% end %> <%= yield %> ================================================ FILE: examples/rails_openid/app/views/login/index.html.erb ================================================ <% if session[:username].nil? %>
Type a username:
<% end %>

Welcome to the Ruby OpenID example. This code is a starting point for developers wishing to implement an OpenID provider or relying party. We've used the Rails platform to demonstrate, but the library code is not Rails specific.

To use the example provider

  1. Enter a username in the form above. You will be "Logged In" to the server, at which point you may authenticate using an OpenID consumer. Your OpenID URL will be displayed after you log in.

    The server will automatically create an identity page for you at <%= @base_url %>user/name

  2. Because WEBrick can only handle one thing at a time, you'll need to run another instance of the example on another port if you want to use a relying party to use with this example provider:

    script/server --port=3001

    (The RP needs to be able to access the provider, so unless you're running this example on a public IP, you can't use the live example at openidenabled.com on your local provider.)

  3. Point your browser to this new instance and follow the directions below.

To use the example relying party

Visit /consumer and enter your OpenID.

================================================ FILE: examples/rails_openid/app/views/server/decide.html.erb ================================================
<% if @oidreq.id_select %> <% else %> <% end %>
Site:<%= @oidreq.trust_root %>
You entered the server identifier at the relying party. You'll need to send an identifier of your choosing. Enter a username below.
Identity to send:
Identity:<%= @oidreq.identity %>
================================================ FILE: examples/rails_openid/config/application.rb ================================================ require File.expand_path('../boot', __FILE__) require 'rails/all' if defined?(Bundler) # If you precompile assets before deploying to production, use this line Bundler.require(*Rails.groups(:assets => %w(development test))) # If you want your assets lazily compiled in production, use this line # Bundler.require(:default, :assets, Rails.env) end module RailsOpenid class Application < Rails::Application # Settings in config/environments/* take precedence over those specified here. # Application configuration should go into files in config/initializers # -- all .rb files in that directory are automatically loaded. # Custom directories with classes and modules you want to be autoloadable. # config.autoload_paths += %W(#{config.root}/extras) # Only load the plugins named here, in the order given (default is alphabetical). # :all can be used as a placeholder for all plugins not explicitly named. # config.plugins = [ :exception_notification, :ssl_requirement, :all ] # Activate observers that should always be running. # config.active_record.observers = :cacher, :garbage_collector, :forum_observer # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. # config.time_zone = 'Central Time (US & Canada)' # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] # config.i18n.default_locale = :de # Configure the default encoding used in templates for Ruby 1.9. config.encoding = "utf-8" # Configure sensitive parameters which will be filtered from the log file. config.filter_parameters += [:password] # Enable escaping HTML in JSON. config.active_support.escape_html_entities_in_json = true # Use SQL instead of Active Record's schema dumper when creating the 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 # Enforce whitelist mode for mass assignment. # This will create an empty whitelist of attributes available for mass-assignment for all models # in your app. As such, your models will need to explicitly whitelist or blacklist accessible # parameters by using an attr_accessible or attr_protected declaration. config.active_record.whitelist_attributes = true # Enable the asset pipeline config.assets.enabled = true # Version of your assets, change this if you want to expire all your assets config.assets.version = '1.0' end end ================================================ FILE: examples/rails_openid/config/boot.rb ================================================ require 'rubygems' # Set up gems listed in the Gemfile. ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) ================================================ FILE: examples/rails_openid/config/database.yml ================================================ # SQLite version 3.x # gem install sqlite3 # # Ensure the SQLite 3 gem is defined in your Gemfile # gem 'sqlite3' development: adapter: sqlite3 database: db/development.sqlite3 pool: 5 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 pool: 5 timeout: 5000 production: adapter: sqlite3 database: db/production.sqlite3 pool: 5 timeout: 5000 ================================================ FILE: examples/rails_openid/config/environment.rb ================================================ # Load the rails application require File.expand_path('../application', __FILE__) # Initialize the rails application RailsOpenid::Application.initialize! ================================================ FILE: examples/rails_openid/config/environments/development.rb ================================================ RailsOpenid::Application.configure do # Settings specified here will take precedence over those in config/application.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 web server when you make code changes. config.cache_classes = false # Log error messages when you accidentally call methods on nil. config.whiny_nils = true # Show full error reports and disable caching config.consider_all_requests_local = true config.action_controller.perform_caching = false # Don't care if the mailer can't send config.action_mailer.raise_delivery_errors = false # Print deprecation notices to the Rails logger config.active_support.deprecation = :log # Only use best-standards-support built into browsers config.action_dispatch.best_standards_support = :builtin # Raise exception on mass assignment protection for Active Record models config.active_record.mass_assignment_sanitizer = :strict # Log the query plan for queries taking more than this (works # with SQLite, MySQL, and PostgreSQL) config.active_record.auto_explain_threshold_in_seconds = 0.5 # Do not compress assets config.assets.compress = false # Expands the lines which load the assets config.assets.debug = true end ================================================ FILE: examples/rails_openid/config/environments/production.rb ================================================ RailsOpenid::Application.configure do # Settings specified here will take precedence over those in config/application.rb # Code is not reloaded between requests config.cache_classes = true # Full error reports are disabled and caching is turned on config.consider_all_requests_local = false config.action_controller.perform_caching = true # Disable Rails's static asset server (Apache or nginx will already do this) config.serve_static_assets = false # Compress JavaScripts and CSS config.assets.compress = true # Don't fallback to assets pipeline if a precompiled asset is missed config.assets.compile = false # Generate digests for assets URLs config.assets.digest = true # Defaults to nil and saved in location specified by config.assets.prefix # config.assets.manifest = YOUR_PATH # Specifies the header that your server uses for sending files # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. # config.force_ssl = true # See everything in the log (default is :info) # config.log_level = :debug # Prepend all log lines with the following tags # config.log_tags = [ :subdomain, :uuid ] # Use a different logger for distributed setups # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) # Use a different cache store in production # config.cache_store = :mem_cache_store # Enable serving of images, stylesheets, and JavaScripts from an asset server # config.action_controller.asset_host = "http://assets.example.com" # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) # config.assets.precompile += %w( search.js ) # Disable delivery errors, bad email addresses will be ignored # config.action_mailer.raise_delivery_errors = false # Enable threaded mode # config.threadsafe! # Enable locale fallbacks for I18n (makes lookups for any locale fall back to # the I18n.default_locale when a translation can not be found) config.i18n.fallbacks = true # Send deprecation notices to registered listeners config.active_support.deprecation = :notify # Log the query plan for queries taking more than this (works # with SQLite, MySQL, and PostgreSQL) # config.active_record.auto_explain_threshold_in_seconds = 0.5 end ================================================ FILE: examples/rails_openid/config/environments/test.rb ================================================ RailsOpenid::Application.configure do # Settings specified here will take precedence over those in config/application.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 # Configure static asset server for tests with Cache-Control for performance config.serve_static_assets = true config.static_cache_control = "public, max-age=3600" # Log error messages when you accidentally call methods on nil config.whiny_nils = true # Show full error reports and disable caching config.consider_all_requests_local = true config.action_controller.perform_caching = false # Raise exceptions instead of rendering exception templates config.action_dispatch.show_exceptions = false # Disable request forgery protection in test environment config.action_controller.allow_forgery_protection = false # Tell Action Mailer not to deliver emails to the real world. # The :test delivery method accumulates sent emails in the # ActionMailer::Base.deliveries array. config.action_mailer.delivery_method = :test # Raise exception on mass assignment protection for Active Record models config.active_record.mass_assignment_sanitizer = :strict # Print deprecation notices to the stderr config.active_support.deprecation = :stderr end ================================================ FILE: examples/rails_openid/config/initializers/backtrace_silencers.rb ================================================ # Be sure to restart your server when you modify this file. # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. # Rails.backtrace_cleaner.remove_silencers! ================================================ FILE: examples/rails_openid/config/initializers/inflections.rb ================================================ # Be sure to restart your server when you modify this file. # Add new inflection rules using the following format # (all these examples are active by default): # ActiveSupport::Inflector.inflections do |inflect| # inflect.plural /^(ox)$/i, '\1en' # inflect.singular /^(ox)en/i, '\1' # inflect.irregular 'person', 'people' # inflect.uncountable %w( fish sheep ) # end # # These inflection rules are supported but not enabled by default: # ActiveSupport::Inflector.inflections do |inflect| # inflect.acronym 'RESTful' # end ================================================ FILE: examples/rails_openid/config/initializers/mime_types.rb ================================================ # 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 ================================================ FILE: examples/rails_openid/config/initializers/rails_root.rb ================================================ ::RAILS_ROOT = Rails.root ================================================ FILE: examples/rails_openid/config/initializers/secret_token.rb ================================================ # Be sure to restart your server when you modify this file. # Your secret key for verifying the integrity of signed cookies. # If you change this key, all old signed cookies will become invalid! # Make sure the secret is at least 30 characters and all random, # no regular words or you'll be exposed to dictionary attacks. RailsOpenid::Application.config.secret_token = '2314c4d00e3702d446505b8df2732c433379a0d61ac94c32a25f71612ab6df457bc9979eb32cae28ad6feacdd5a9ae7ac330934c5fb53877e02ce8e23ac0f494' ================================================ FILE: examples/rails_openid/config/initializers/session_store.rb ================================================ # Be sure to restart your server when you modify this file. RailsOpenid::Application.config.session_store :cookie_store, :key => '_rails_openid_session' # Use the database for sessions instead of the cookie-based default, # which shouldn't be used to store highly confidential information # (create the session table with "rails generate session_migration") # RailsOpenid::Application.config.session_store :active_record_store ================================================ FILE: examples/rails_openid/config/initializers/wrap_parameters.rb ================================================ # Be sure to restart your server when you modify this file. # # This file contains settings for ActionController::ParamsWrapper which # is enabled by default. # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. ActiveSupport.on_load(:action_controller) do wrap_parameters :format => [:json] end # Disable root element in JSON by default. ActiveSupport.on_load(:active_record) do self.include_root_in_json = false end ================================================ FILE: examples/rails_openid/config/locales/en.yml ================================================ # Sample localization file for English. Add more files in this directory for other locales. # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. en: hello: "Hello world" ================================================ FILE: examples/rails_openid/config/routes.rb ================================================ RailsOpenid::Application.routes.draw do root :controller => 'login', :action => :index match 'server/xrds', :controller => 'server', :action => 'idp_xrds' match 'user/:username', :controller => 'server', :action => 'user_page' match 'user/:username/xrds', :controller => 'server', :action => 'user_xrds' # Allow downloading Web Service WSDL as a file with an extension # instead of a file named 'wsdl' match ':controller/service.wsdl', :action => 'wsdl' # Install the default route as the lowest priority. match ':controller/:action/:id' # The priority is based upon order of creation: # first created -> highest priority. # Sample of regular route: # match 'products/:id' => 'catalog#view' # Keep in mind you can assign values other than :controller and :action # Sample of named route: # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase # This route can be invoked with purchase_url(:id => product.id) # Sample resource route (maps HTTP verbs to controller actions automatically): # resources :products # Sample resource route with options: # resources :products do # member do # get 'short' # post 'toggle' # end # # collection do # get 'sold' # end # end # Sample resource route with sub-resources: # resources :products do # resources :comments, :sales # resource :seller # end # Sample resource route with more complex sub-resources # resources :products do # resources :comments # resources :sales do # get 'recent', :on => :collection # end # end # Sample resource route within a namespace: # namespace :admin do # # Directs /admin/products/* to Admin::ProductsController # # (app/controllers/admin/products_controller.rb) # resources :products # end # You can have the root of your site routed with "root" # just remember to delete public/index.html. # root :to => 'welcome#index' # See how all your routes lay out with "rake routes" # This is a legacy wild controller route that's not recommended for RESTful applications. # Note: This route will make all actions in every controller accessible via GET requests. match ':controller(/:action(/:id))(.:format)' end ================================================ FILE: examples/rails_openid/config.ru ================================================ # This file is used by Rack-based servers to start the application. require ::File.expand_path('../config/environment', __FILE__) run RailsOpenid::Application ================================================ FILE: examples/rails_openid/db/development.sqlite3 ================================================ ================================================ FILE: examples/rails_openid/db/seeds.rb ================================================ # This file should contain all the record creation needed to seed the database with its default values. # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). # # Examples: # # cities = City.create([{ :name => 'Chicago' }, { :name => 'Copenhagen' }]) # Mayor.create(:name => 'Emanuel', :city => cities.first) ================================================ FILE: examples/rails_openid/lib/assets/.gitkeep ================================================ ================================================ FILE: examples/rails_openid/lib/tasks/.gitkeep ================================================ ================================================ FILE: examples/rails_openid/log/.gitkeep ================================================ ================================================ FILE: examples/rails_openid/log/development.log ================================================ Connecting to database specified by database.yml Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 05:22:11 -0700 2013 ActionController::RoutingError (No route matches [GET] "/consumer"): actionpack (3.2.13) lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/show_exceptions.rb:56:in `call' railties (3.2.13) lib/rails/rack/logger.rb:32:in `call_app' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' activesupport (3.2.13) lib/active_support/tagged_logging.rb:22:in `tagged' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/request_id.rb:22:in `call' rack (1.4.5) lib/rack/methodoverride.rb:21:in `call' rack (1.4.5) lib/rack/runtime.rb:17:in `call' activesupport (3.2.13) lib/active_support/cache/strategy/local_cache.rb:72:in `call' rack (1.4.5) lib/rack/lock.rb:15:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/static.rb:63:in `call' railties (3.2.13) lib/rails/engine.rb:479:in `call' railties (3.2.13) lib/rails/application.rb:223:in `call' rack (1.4.5) lib/rack/content_length.rb:14:in `call' railties (3.2.13) lib/rails/rack/log_tailer.rb:17:in `call' rack (1.4.5) lib/rack/handler/webrick.rb:59:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:104:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:65:in `run' /opt/local/lib/ruby/1.8/webrick/server.rb:173:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:95:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `each' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:23:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:82:in `start' rack (1.4.5) lib/rack/handler/webrick.rb:13:in `run' rack (1.4.5) lib/rack/server.rb:268:in `start' railties (3.2.13) lib/rails/commands/server.rb:70:in `start' railties (3.2.13) lib/rails/commands.rb:55 railties (3.2.13) lib/rails/commands.rb:50:in `tap' railties (3.2.13) lib/rails/commands.rb:50 script/rails:6:in `require' script/rails:6 Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/routing_error.erb within rescues/layout (3.3ms) Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 05:23:00 -0700 2013 LoadError (no such file to load -- openid): app/controllers/consumer_controller.rb:3 Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.8ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (13.8ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (31.1ms) Connecting to database specified by database.yml Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 05:23:40 -0700 2013 Processing by ConsumerController#index as HTML Completed 500 Internal Server Error in 24ms ActionView::MissingTemplate (Missing template consumer/index, application/index with {:handlers=>[:coffee, :erb, :builder], :locale=>[:en], :formats=>[:html]}. Searched in: * "/Users/marcel/.gem/ruby/1.8/gems/ruby-openid-2.2.3/examples/rails_openid/app/views" ): actionpack (3.2.13) lib/action_view/path_set.rb:58:in `find' actionpack (3.2.13) lib/action_view/lookup_context.rb:109:in `find_template' actionpack (3.2.13) lib/action_view/renderer/abstract_renderer.rb:3:in `__send__' actionpack (3.2.13) lib/action_view/renderer/abstract_renderer.rb:3:in `find_template' actionpack (3.2.13) lib/action_view/renderer/template_renderer.rb:34:in `determine_template' actionpack (3.2.13) lib/action_view/renderer/template_renderer.rb:10:in `render' actionpack (3.2.13) lib/action_view/renderer/renderer.rb:36:in `render_template' actionpack (3.2.13) lib/action_view/renderer/renderer.rb:17:in `render' actionpack (3.2.13) lib/abstract_controller/rendering.rb:110:in `_render_template' actionpack (3.2.13) lib/action_controller/metal/streaming.rb:225:in `_render_template' actionpack (3.2.13) lib/abstract_controller/rendering.rb:103:in `render_to_body' actionpack (3.2.13) lib/action_controller/metal/renderers.rb:28:in `render_to_body' actionpack (3.2.13) lib/action_controller/metal/compatibility.rb:50:in `render_to_body' actionpack (3.2.13) lib/abstract_controller/rendering.rb:88:in `render' actionpack (3.2.13) lib/action_controller/metal/rendering.rb:16:in `render' actionpack (3.2.13) lib/action_controller/metal/instrumentation.rb:40:in `render' activesupport (3.2.13) lib/active_support/core_ext/benchmark.rb:5:in `ms' /opt/local/lib/ruby/1.8/benchmark.rb:308:in `realtime' activesupport (3.2.13) lib/active_support/core_ext/benchmark.rb:5:in `ms' actionpack (3.2.13) lib/action_controller/metal/instrumentation.rb:40:in `render' actionpack (3.2.13) lib/action_controller/metal/instrumentation.rb:83:in `cleanup_view_runtime' activerecord (3.2.13) lib/active_record/railties/controller_runtime.rb:24:in `cleanup_view_runtime' actionpack (3.2.13) lib/action_controller/metal/instrumentation.rb:39:in `render' actionpack (3.2.13) lib/action_controller/metal/implicit_render.rb:10:in `default_render' actionpack (3.2.13) lib/action_controller/metal/implicit_render.rb:5:in `send_action' actionpack (3.2.13) lib/abstract_controller/base.rb:167:in `process_action' actionpack (3.2.13) lib/action_controller/metal/rendering.rb:10:in `process_action' actionpack (3.2.13) lib/abstract_controller/callbacks.rb:18:in `process_action' activesupport (3.2.13) lib/active_support/callbacks.rb:414:in `_run__1789127949__process_action__199225275__callbacks' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `send' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `__run_callback' activesupport (3.2.13) lib/active_support/callbacks.rb:385:in `_run_process_action_callbacks' activesupport (3.2.13) lib/active_support/callbacks.rb:81:in `send' activesupport (3.2.13) lib/active_support/callbacks.rb:81:in `run_callbacks' actionpack (3.2.13) lib/abstract_controller/callbacks.rb:17:in `process_action' actionpack (3.2.13) lib/action_controller/metal/rescue.rb:29:in `process_action' actionpack (3.2.13) lib/action_controller/metal/instrumentation.rb:30:in `process_action' activesupport (3.2.13) lib/active_support/notifications.rb:123:in `instrument' activesupport (3.2.13) lib/active_support/notifications/instrumenter.rb:20:in `instrument' activesupport (3.2.13) lib/active_support/notifications.rb:123:in `instrument' actionpack (3.2.13) lib/action_controller/metal/instrumentation.rb:29:in `process_action' actionpack (3.2.13) lib/action_controller/metal/params_wrapper.rb:207:in `process_action' activerecord (3.2.13) lib/active_record/railties/controller_runtime.rb:18:in `process_action' actionpack (3.2.13) lib/abstract_controller/base.rb:121:in `process' actionpack (3.2.13) lib/abstract_controller/rendering.rb:45:in `process' actionpack (3.2.13) lib/action_controller/metal.rb:203:in `dispatch' actionpack (3.2.13) lib/action_controller/metal/rack_delegation.rb:14:in `dispatch' actionpack (3.2.13) lib/action_controller/metal.rb:246:in `action' actionpack (3.2.13) lib/action_dispatch/routing/route_set.rb:73:in `call' actionpack (3.2.13) lib/action_dispatch/routing/route_set.rb:73:in `dispatch' actionpack (3.2.13) lib/action_dispatch/routing/route_set.rb:36:in `call' journey (1.0.4) lib/journey/router.rb:68:in `call' journey (1.0.4) lib/journey/router.rb:56:in `each' journey (1.0.4) lib/journey/router.rb:56:in `call' actionpack (3.2.13) lib/action_dispatch/routing/route_set.rb:612:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/best_standards_support.rb:17:in `call' rack (1.4.5) lib/rack/etag.rb:23:in `call' rack (1.4.5) lib/rack/conditionalget.rb:25:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/head.rb:14:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/params_parser.rb:21:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/flash.rb:242:in `call' rack (1.4.5) lib/rack/session/abstract/id.rb:210:in `context' rack (1.4.5) lib/rack/session/abstract/id.rb:205:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/cookies.rb:341:in `call' activerecord (3.2.13) lib/active_record/query_cache.rb:64:in `call' activerecord (3.2.13) lib/active_record/connection_adapters/abstract/connection_pool.rb:479:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/callbacks.rb:28:in `call' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `_run__397314981__call__4__callbacks' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `send' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `__run_callback' activesupport (3.2.13) lib/active_support/callbacks.rb:385:in `_run_call_callbacks' activesupport (3.2.13) lib/active_support/callbacks.rb:81:in `send' activesupport (3.2.13) lib/active_support/callbacks.rb:81:in `run_callbacks' actionpack (3.2.13) lib/action_dispatch/middleware/callbacks.rb:27:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/reloader.rb:65:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/remote_ip.rb:31:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/debug_exceptions.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/show_exceptions.rb:56:in `call' railties (3.2.13) lib/rails/rack/logger.rb:32:in `call_app' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' activesupport (3.2.13) lib/active_support/tagged_logging.rb:22:in `tagged' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/request_id.rb:22:in `call' rack (1.4.5) lib/rack/methodoverride.rb:21:in `call' rack (1.4.5) lib/rack/runtime.rb:17:in `call' activesupport (3.2.13) lib/active_support/cache/strategy/local_cache.rb:72:in `call' rack (1.4.5) lib/rack/lock.rb:15:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/static.rb:63:in `call' railties (3.2.13) lib/rails/engine.rb:479:in `call' railties (3.2.13) lib/rails/application.rb:223:in `call' rack (1.4.5) lib/rack/content_length.rb:14:in `call' railties (3.2.13) lib/rails/rack/log_tailer.rb:17:in `call' rack (1.4.5) lib/rack/handler/webrick.rb:59:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:104:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:65:in `run' /opt/local/lib/ruby/1.8/webrick/server.rb:173:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:95:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `each' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:23:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:82:in `start' rack (1.4.5) lib/rack/handler/webrick.rb:13:in `run' rack (1.4.5) lib/rack/server.rb:268:in `start' railties (3.2.13) lib/rails/commands/server.rb:70:in `start' railties (3.2.13) lib/rails/commands.rb:55 railties (3.2.13) lib/rails/commands.rb:50:in `tap' railties (3.2.13) lib/rails/commands.rb:50 script/rails:6:in `require' script/rails:6 Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/missing_template.erb within rescues/layout (1.9ms) Connecting to database specified by database.yml Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 05:25:07 -0700 2013 Processing by ConsumerController#index as HTML Rendered consumer/index.html.erb within layouts/application (6.1ms) Compiled application.css (1ms) (pid 67167) Compiled jquery.js (13ms) (pid 67167) Compiled jquery_ujs.js (1ms) (pid 67167) Compiled application.js (113ms) (pid 67167) Completed 200 OK in 426ms (Views: 425.4ms | ActiveRecord: 0.0ms) Started GET "/assets/application.css?body=1" for 127.0.0.1 at Sun Mar 31 05:25:09 -0700 2013 Served asset /application.css - 200 OK (4ms) Started GET "/assets/jquery.js?body=1" for 127.0.0.1 at Sun Mar 31 05:25:09 -0700 2013 Served asset /jquery.js - 200 OK (15ms) Started GET "/assets/jquery_ujs.js?body=1" for 127.0.0.1 at Sun Mar 31 05:25:09 -0700 2013 Served asset /jquery_ujs.js - 200 OK (13ms) Started GET "/assets/application.js?body=1" for 127.0.0.1 at Sun Mar 31 05:25:09 -0700 2013 Served asset /application.js - 200 OK (32ms) Started GET "/consumer/start?openid_identifier=http%3A%2F%2Flocalhost%3A3009%2Fopen_id%2Fmarcel" for 127.0.0.1 at Sun Mar 31 05:25:22 -0700 2013 Processing by ConsumerController#start as HTML Parameters: {"openid_identifier"=>"http://localhost:3009/open_id/marcel"} Completed 500 Internal Server Error in 2ms NameError (uninitialized constant ConsumerController::RAILS_ROOT): app/controllers/consumer_controller.rb:116:in `consumer' app/controllers/consumer_controller.rb:23:in `start' Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.8ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (2.1ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (121.5ms) Connecting to database specified by database.yml Started GET "/consumer/start?openid_identifier=http%3A%2F%2Flocalhost%3A3009%2Fopen_id%2Fmarcel" for 127.0.0.1 at Sun Mar 31 05:26:13 -0700 2013 Processing by ConsumerController#start as HTML Parameters: {"openid_identifier"=>"http://localhost:3009/open_id/marcel"} Redirected to http://localhost:3009/open_id/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582b66%7D%7BvdrbdQ%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fopen_id%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fopen_id%2Fmarcel&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete Completed 302 Found in 661ms (ActiveRecord: 0.0ms) Started GET "/consumer/complete?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582b69%7D%7BodxU%2BQ%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fopen_id%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fopen_id%2Fmarcel&openid.invalidate_handle=%7BHMAC-SHA1%7D%7B51582b66%7D%7BvdrbdQ%3D%3D%7D&openid.mode=id_res&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.op_endpoint=http%3A%2F%2Flocalhost%3A3009%2Fopen_id%2Fserver&openid.response_nonce=2013-03-31T12%3A26%3A17ZVVzuGN&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete&openid.sig=HHdHfhXu%2FmKVDXkCffxuD%2BYuNeU%3D&openid.signed=assoc_handle%2Cclaimed_id%2Cidentity%2Cinvalidate_handle%2Cmode%2Cns%2Cop_endpoint%2Cresponse_nonce%2Creturn_to%2Csigned" for 127.0.0.1 at Sun Mar 31 05:26:17 -0700 2013 Processing by ConsumerController#complete as HTML Parameters: {"openid.sig"=>"HHdHfhXu/mKVDXkCffxuD+YuNeU=", "openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.op_endpoint"=>"http://localhost:3009/open_id/server", "openid.mode"=>"id_res", "openid.response_nonce"=>"2013-03-31T12:26:17ZVVzuGN", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://localhost:3009/open_id/marcel", "openid.signed"=>"assoc_handle,claimed_id,identity,invalidate_handle,mode,ns,op_endpoint,response_nonce,return_to,signed", "openid.invalidate_handle"=>"{HMAC-SHA1}{51582b66}{vdrbdQ==}", "openid.assoc_handle"=>"{HMAC-SHA1}{51582b69}{odxU+Q==}", "openid.claimed_id"=>"http://localhost:3009/open_id/marcel"} Redirected to http://localhost:3010/consumer Completed 302 Found in 4ms (ActiveRecord: 0.0ms) Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 05:26:17 -0700 2013 Processing by ConsumerController#index as HTML Rendered consumer/index.html.erb within layouts/application (14.7ms) Completed 200 OK in 59ms (Views: 58.8ms | ActiveRecord: 0.0ms) Started GET "/assets/application.js?body=1" for 127.0.0.1 at Sun Mar 31 05:26:17 -0700 2013 Served asset /application.js - 304 Not Modified (8ms) Started GET "/assets/application.css?body=1" for 127.0.0.1 at Sun Mar 31 05:26:17 -0700 2013 Served asset /application.css - 304 Not Modified (132ms) Connecting to database specified by database.yml Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 05:30:38 -0700 2013 ActionDispatch::Session::SessionRestoreError (Session contains objects whose class definition isn't available. Remember to require the classes for all objects kept in the session. (Original exception: uninitialized constant OpenID [NameError]) ): actionpack (3.2.13) lib/action_dispatch/middleware/session/abstract_store.rb:64:in `stale_session_check!' actionpack (3.2.13) lib/action_dispatch/middleware/session/cookie_store.rb:48:in `unpacked_cookie_data' rack (1.4.5) lib/rack/session/cookie.rb:107:in `extract_session_id' actionpack (3.2.13) lib/action_dispatch/middleware/session/abstract_store.rb:53:in `extract_session_id' actionpack (3.2.13) lib/action_dispatch/middleware/session/abstract_store.rb:57:in `stale_session_check!' actionpack (3.2.13) lib/action_dispatch/middleware/session/abstract_store.rb:53:in `extract_session_id' rack (1.4.5) lib/rack/session/abstract/id.rb:43:in `send' rack (1.4.5) lib/rack/session/abstract/id.rb:43:in `load_session_id!' rack (1.4.5) lib/rack/session/abstract/id.rb:32:in `[]' rack (1.4.5) lib/rack/session/abstract/id.rb:267:in `current_session_id' rack (1.4.5) lib/rack/session/abstract/id.rb:273:in `session_exists?' rack (1.4.5) lib/rack/session/abstract/id.rb:107:in `send' rack (1.4.5) lib/rack/session/abstract/id.rb:107:in `exists?' rack (1.4.5) lib/rack/session/abstract/id.rb:127:in `load_for_read!' rack (1.4.5) lib/rack/session/abstract/id.rb:64:in `key?' actionpack (3.2.13) lib/action_dispatch/middleware/flash.rb:258:in `call' rack (1.4.5) lib/rack/session/abstract/id.rb:210:in `context' rack (1.4.5) lib/rack/session/abstract/id.rb:205:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/cookies.rb:341:in `call' activerecord (3.2.13) lib/active_record/query_cache.rb:64:in `call' activerecord (3.2.13) lib/active_record/connection_adapters/abstract/connection_pool.rb:479:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/callbacks.rb:28:in `call' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `_run__397314981__call__4__callbacks' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `send' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `__run_callback' activesupport (3.2.13) lib/active_support/callbacks.rb:385:in `_run_call_callbacks' activesupport (3.2.13) lib/active_support/callbacks.rb:81:in `send' activesupport (3.2.13) lib/active_support/callbacks.rb:81:in `run_callbacks' actionpack (3.2.13) lib/action_dispatch/middleware/callbacks.rb:27:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/reloader.rb:65:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/remote_ip.rb:31:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/debug_exceptions.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/show_exceptions.rb:56:in `call' railties (3.2.13) lib/rails/rack/logger.rb:32:in `call_app' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' activesupport (3.2.13) lib/active_support/tagged_logging.rb:22:in `tagged' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/request_id.rb:22:in `call' rack (1.4.5) lib/rack/methodoverride.rb:21:in `call' rack (1.4.5) lib/rack/runtime.rb:17:in `call' activesupport (3.2.13) lib/active_support/cache/strategy/local_cache.rb:72:in `call' rack (1.4.5) lib/rack/lock.rb:15:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/static.rb:63:in `call' railties (3.2.13) lib/rails/engine.rb:479:in `call' railties (3.2.13) lib/rails/application.rb:223:in `call' rack (1.4.5) lib/rack/content_length.rb:14:in `call' railties (3.2.13) lib/rails/rack/log_tailer.rb:17:in `call' rack (1.4.5) lib/rack/handler/webrick.rb:59:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:104:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:65:in `run' /opt/local/lib/ruby/1.8/webrick/server.rb:173:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:95:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `each' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:23:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:82:in `start' rack (1.4.5) lib/rack/handler/webrick.rb:13:in `run' rack (1.4.5) lib/rack/server.rb:268:in `start' railties (3.2.13) lib/rails/commands/server.rb:70:in `start' railties (3.2.13) lib/rails/commands.rb:55 railties (3.2.13) lib/rails/commands.rb:50:in `tap' railties (3.2.13) lib/rails/commands.rb:50 script/rails:6:in `require' script/rails:6 Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.8ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (4.6ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (23.6ms) Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 05:30:45 -0700 2013 ActionDispatch::Session::SessionRestoreError (Session contains objects whose class definition isn't available. Remember to require the classes for all objects kept in the session. (Original exception: uninitialized constant OpenID [NameError]) ): actionpack (3.2.13) lib/action_dispatch/middleware/session/abstract_store.rb:64:in `stale_session_check!' actionpack (3.2.13) lib/action_dispatch/middleware/session/cookie_store.rb:48:in `unpacked_cookie_data' rack (1.4.5) lib/rack/session/cookie.rb:107:in `extract_session_id' actionpack (3.2.13) lib/action_dispatch/middleware/session/abstract_store.rb:53:in `extract_session_id' actionpack (3.2.13) lib/action_dispatch/middleware/session/abstract_store.rb:57:in `stale_session_check!' actionpack (3.2.13) lib/action_dispatch/middleware/session/abstract_store.rb:53:in `extract_session_id' rack (1.4.5) lib/rack/session/abstract/id.rb:43:in `send' rack (1.4.5) lib/rack/session/abstract/id.rb:43:in `load_session_id!' rack (1.4.5) lib/rack/session/abstract/id.rb:32:in `[]' rack (1.4.5) lib/rack/session/abstract/id.rb:267:in `current_session_id' rack (1.4.5) lib/rack/session/abstract/id.rb:273:in `session_exists?' rack (1.4.5) lib/rack/session/abstract/id.rb:107:in `send' rack (1.4.5) lib/rack/session/abstract/id.rb:107:in `exists?' rack (1.4.5) lib/rack/session/abstract/id.rb:127:in `load_for_read!' rack (1.4.5) lib/rack/session/abstract/id.rb:64:in `key?' actionpack (3.2.13) lib/action_dispatch/middleware/flash.rb:258:in `call' rack (1.4.5) lib/rack/session/abstract/id.rb:210:in `context' rack (1.4.5) lib/rack/session/abstract/id.rb:205:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/cookies.rb:341:in `call' activerecord (3.2.13) lib/active_record/query_cache.rb:64:in `call' activerecord (3.2.13) lib/active_record/connection_adapters/abstract/connection_pool.rb:479:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/callbacks.rb:28:in `call' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `_run__397314981__call__4__callbacks' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `send' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `__run_callback' activesupport (3.2.13) lib/active_support/callbacks.rb:385:in `_run_call_callbacks' activesupport (3.2.13) lib/active_support/callbacks.rb:81:in `send' activesupport (3.2.13) lib/active_support/callbacks.rb:81:in `run_callbacks' actionpack (3.2.13) lib/action_dispatch/middleware/callbacks.rb:27:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/reloader.rb:65:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/remote_ip.rb:31:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/debug_exceptions.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/show_exceptions.rb:56:in `call' railties (3.2.13) lib/rails/rack/logger.rb:32:in `call_app' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' activesupport (3.2.13) lib/active_support/tagged_logging.rb:22:in `tagged' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/request_id.rb:22:in `call' rack (1.4.5) lib/rack/methodoverride.rb:21:in `call' rack (1.4.5) lib/rack/runtime.rb:17:in `call' activesupport (3.2.13) lib/active_support/cache/strategy/local_cache.rb:72:in `call' rack (1.4.5) lib/rack/lock.rb:15:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/static.rb:63:in `call' railties (3.2.13) lib/rails/engine.rb:479:in `call' railties (3.2.13) lib/rails/application.rb:223:in `call' rack (1.4.5) lib/rack/content_length.rb:14:in `call' railties (3.2.13) lib/rails/rack/log_tailer.rb:17:in `call' rack (1.4.5) lib/rack/handler/webrick.rb:59:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:104:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:65:in `run' /opt/local/lib/ruby/1.8/webrick/server.rb:173:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:95:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `each' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:23:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:82:in `start' rack (1.4.5) lib/rack/handler/webrick.rb:13:in `run' rack (1.4.5) lib/rack/server.rb:268:in `start' railties (3.2.13) lib/rails/commands/server.rb:70:in `start' railties (3.2.13) lib/rails/commands.rb:55 railties (3.2.13) lib/rails/commands.rb:50:in `tap' railties (3.2.13) lib/rails/commands.rb:50 script/rails:6:in `require' script/rails:6 Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.8ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (1.1ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (18.9ms) Connecting to database specified by database.yml Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 05:31:30 -0700 2013 Processing by ConsumerController#index as HTML Rendered consumer/index.html.erb within layouts/application (7.0ms) Completed 200 OK in 198ms (Views: 197.4ms | ActiveRecord: 0.0ms) Started GET "/assets/jquery.js?body=1" for 127.0.0.1 at Sun Mar 31 05:31:31 -0700 2013 Served asset /jquery.js - 304 Not Modified (7ms) Started GET "/assets/application.css?body=1" for 127.0.0.1 at Sun Mar 31 05:31:31 -0700 2013 Served asset /application.css - 304 Not Modified (3ms) Started GET "/assets/application.js?body=1" for 127.0.0.1 at Sun Mar 31 05:31:31 -0700 2013 Served asset /application.js - 304 Not Modified (44ms) Started GET "/consumer/start?openid_identifier=http%3A%2F%2Flocalhost%3A3009%2Fopen_id%2Fmarcel" for 127.0.0.1 at Sun Mar 31 05:31:36 -0700 2013 Processing by ConsumerController#start as HTML Parameters: {"openid_identifier"=>"http://localhost:3009/open_id/marcel"} Redirected to http://localhost:3009/open_id/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582b66%7D%7BvdrbdQ%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fopen_id%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fopen_id%2Fmarcel&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete Completed 302 Found in 65ms (ActiveRecord: 0.0ms) Started GET "/consumer/complete?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582cb5%7D%7B2olQew%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fopen_id%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fopen_id%2Fmarcel&openid.invalidate_handle=%7BHMAC-SHA1%7D%7B51582b66%7D%7BvdrbdQ%3D%3D%7D&openid.mode=id_res&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.op_endpoint=http%3A%2F%2Flocalhost%3A3009%2Fopen_id%2Fserver&openid.response_nonce=2013-03-31T12%3A31%3A49Z8CDJUo&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete&openid.sig=skvSU5yuQsW%2BZwCkDbUbGmtMngc%3D&openid.signed=assoc_handle%2Cclaimed_id%2Cidentity%2Cinvalidate_handle%2Cmode%2Cns%2Cop_endpoint%2Cresponse_nonce%2Creturn_to%2Csigned" for 127.0.0.1 at Sun Mar 31 05:31:49 -0700 2013 Processing by ConsumerController#complete as HTML Parameters: {"openid.sig"=>"skvSU5yuQsW+ZwCkDbUbGmtMngc=", "openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.op_endpoint"=>"http://localhost:3009/open_id/server", "openid.mode"=>"id_res", "openid.response_nonce"=>"2013-03-31T12:31:49Z8CDJUo", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://localhost:3009/open_id/marcel", "openid.signed"=>"assoc_handle,claimed_id,identity,invalidate_handle,mode,ns,op_endpoint,response_nonce,return_to,signed", "openid.invalidate_handle"=>"{HMAC-SHA1}{51582b66}{vdrbdQ==}", "openid.assoc_handle"=>"{HMAC-SHA1}{51582cb5}{2olQew==}", "openid.claimed_id"=>"http://localhost:3009/open_id/marcel"} Redirected to http://localhost:3010/consumer Completed 302 Found in 65ms (ActiveRecord: 0.0ms) Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 05:31:49 -0700 2013 Processing by ConsumerController#index as HTML Rendered consumer/index.html.erb within layouts/application (0.7ms) Completed 200 OK in 7ms (Views: 6.9ms | ActiveRecord: 0.0ms) Started GET "/assets/jquery.js?body=1" for 127.0.0.1 at Sun Mar 31 05:31:49 -0700 2013 Served asset /jquery.js - 304 Not Modified (0ms) Started GET "/assets/application.css?body=1" for 127.0.0.1 at Sun Mar 31 05:31:49 -0700 2013 Served asset /application.css - 304 Not Modified (0ms) Started GET "/assets/application.js?body=1" for 127.0.0.1 at Sun Mar 31 05:31:49 -0700 2013 Served asset /application.js - 304 Not Modified (0ms) Connecting to database specified by database.yml Started GET "/server" for 127.0.0.1 at Sun Mar 31 05:32:59 -0700 2013 ActionDispatch::Session::SessionRestoreError (Session contains objects whose class definition isn't available. Remember to require the classes for all objects kept in the session. (Original exception: uninitialized constant OpenID [NameError]) ): actionpack (3.2.13) lib/action_dispatch/middleware/session/abstract_store.rb:64:in `stale_session_check!' actionpack (3.2.13) lib/action_dispatch/middleware/session/cookie_store.rb:48:in `unpacked_cookie_data' rack (1.4.5) lib/rack/session/cookie.rb:107:in `extract_session_id' actionpack (3.2.13) lib/action_dispatch/middleware/session/abstract_store.rb:53:in `extract_session_id' actionpack (3.2.13) lib/action_dispatch/middleware/session/abstract_store.rb:57:in `stale_session_check!' actionpack (3.2.13) lib/action_dispatch/middleware/session/abstract_store.rb:53:in `extract_session_id' rack (1.4.5) lib/rack/session/abstract/id.rb:43:in `send' rack (1.4.5) lib/rack/session/abstract/id.rb:43:in `load_session_id!' rack (1.4.5) lib/rack/session/abstract/id.rb:32:in `[]' rack (1.4.5) lib/rack/session/abstract/id.rb:267:in `current_session_id' rack (1.4.5) lib/rack/session/abstract/id.rb:273:in `session_exists?' rack (1.4.5) lib/rack/session/abstract/id.rb:107:in `send' rack (1.4.5) lib/rack/session/abstract/id.rb:107:in `exists?' rack (1.4.5) lib/rack/session/abstract/id.rb:127:in `load_for_read!' rack (1.4.5) lib/rack/session/abstract/id.rb:64:in `key?' actionpack (3.2.13) lib/action_dispatch/middleware/flash.rb:258:in `call' rack (1.4.5) lib/rack/session/abstract/id.rb:210:in `context' rack (1.4.5) lib/rack/session/abstract/id.rb:205:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/cookies.rb:341:in `call' activerecord (3.2.13) lib/active_record/query_cache.rb:64:in `call' activerecord (3.2.13) lib/active_record/connection_adapters/abstract/connection_pool.rb:479:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/callbacks.rb:28:in `call' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `_run__397314981__call__4__callbacks' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `send' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `__run_callback' activesupport (3.2.13) lib/active_support/callbacks.rb:385:in `_run_call_callbacks' activesupport (3.2.13) lib/active_support/callbacks.rb:81:in `send' activesupport (3.2.13) lib/active_support/callbacks.rb:81:in `run_callbacks' actionpack (3.2.13) lib/action_dispatch/middleware/callbacks.rb:27:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/reloader.rb:65:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/remote_ip.rb:31:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/debug_exceptions.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/show_exceptions.rb:56:in `call' railties (3.2.13) lib/rails/rack/logger.rb:32:in `call_app' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' activesupport (3.2.13) lib/active_support/tagged_logging.rb:22:in `tagged' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/request_id.rb:22:in `call' rack (1.4.5) lib/rack/methodoverride.rb:21:in `call' rack (1.4.5) lib/rack/runtime.rb:17:in `call' activesupport (3.2.13) lib/active_support/cache/strategy/local_cache.rb:72:in `call' rack (1.4.5) lib/rack/lock.rb:15:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/static.rb:63:in `call' railties (3.2.13) lib/rails/engine.rb:479:in `call' railties (3.2.13) lib/rails/application.rb:223:in `call' rack (1.4.5) lib/rack/content_length.rb:14:in `call' railties (3.2.13) lib/rails/rack/log_tailer.rb:17:in `call' rack (1.4.5) lib/rack/handler/webrick.rb:59:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:104:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:65:in `run' /opt/local/lib/ruby/1.8/webrick/server.rb:173:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:95:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `each' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:23:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:82:in `start' rack (1.4.5) lib/rack/handler/webrick.rb:13:in `run' rack (1.4.5) lib/rack/server.rb:268:in `start' railties (3.2.13) lib/rails/commands/server.rb:70:in `start' railties (3.2.13) lib/rails/commands.rb:55 railties (3.2.13) lib/rails/commands.rb:50:in `tap' railties (3.2.13) lib/rails/commands.rb:50 script/rails:6:in `require' script/rails:6 Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.9ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (2.0ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (19.9ms) Started GET "/server" for 127.0.0.1 at Sun Mar 31 05:33:19 -0700 2013 Processing by ServerController#index as HTML Rendered text template (0.0ms) Completed 500 Internal Server Error in 31ms (Views: 25.3ms | ActiveRecord: 0.0ms) Started GET "/server" for 127.0.0.1 at Sun Mar 31 05:33:41 -0700 2013 Processing by ServerController#index as HTML Rendered text template (0.0ms) Completed 500 Internal Server Error in 5ms (Views: 2.7ms | ActiveRecord: 0.0ms) Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 05:33:47 -0700 2013 Processing by ConsumerController#index as HTML Rendered consumer/index.html.erb within layouts/application (0.8ms) Completed 200 OK in 11ms (Views: 10.3ms | ActiveRecord: 0.0ms) Started GET "/assets/jquery.js?body=1" for 127.0.0.1 at Sun Mar 31 05:33:47 -0700 2013 Served asset /jquery.js - 304 Not Modified (0ms) Started GET "/assets/application.js?body=1" for 127.0.0.1 at Sun Mar 31 05:33:47 -0700 2013 Served asset /application.js - 304 Not Modified (0ms) Started GET "/assets/application.css?body=1" for 127.0.0.1 at Sun Mar 31 05:33:47 -0700 2013 Served asset /application.css - 304 Not Modified (0ms) Started GET "/consumer/start?openid_identifier=http%3A%2F%2Flocalhost%3A3009%2Fopen_id%2Fmarcel" for 127.0.0.1 at Sun Mar 31 05:33:57 -0700 2013 Processing by ConsumerController#start as HTML Parameters: {"openid_identifier"=>"http://localhost:3009/open_id/marcel"} Started GET "/open_id/marcel" for 127.0.0.1 at Sun Mar 31 05:33:57 -0700 2013 ActionController::RoutingError (No route matches [GET] "/open_id/marcel"): actionpack (3.2.13) lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/show_exceptions.rb:56:in `call' railties (3.2.13) lib/rails/rack/logger.rb:32:in `call_app' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' activesupport (3.2.13) lib/active_support/tagged_logging.rb:22:in `tagged' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/request_id.rb:22:in `call' rack (1.4.5) lib/rack/methodoverride.rb:21:in `call' rack (1.4.5) lib/rack/runtime.rb:17:in `call' activesupport (3.2.13) lib/active_support/cache/strategy/local_cache.rb:72:in `call' rack (1.4.5) lib/rack/lock.rb:15:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/static.rb:63:in `call' railties (3.2.13) lib/rails/engine.rb:479:in `call' railties (3.2.13) lib/rails/application.rb:223:in `call' rack (1.4.5) lib/rack/content_length.rb:14:in `call' railties (3.2.13) lib/rails/rack/log_tailer.rb:17:in `call' rack (1.4.5) lib/rack/handler/webrick.rb:59:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:104:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:65:in `run' /opt/local/lib/ruby/1.8/webrick/server.rb:173:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:95:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `each' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:23:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:82:in `start' rack (1.4.5) lib/rack/handler/webrick.rb:13:in `run' rack (1.4.5) lib/rack/server.rb:268:in `start' railties (3.2.13) lib/rails/commands/server.rb:70:in `start' railties (3.2.13) lib/rails/commands.rb:55 railties (3.2.13) lib/rails/commands.rb:50:in `tap' railties (3.2.13) lib/rails/commands.rb:50 script/rails:6:in `require' script/rails:6 Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/routing_error.erb within rescues/layout (0.6ms) Redirected to http://localhost:3010/consumer Completed 302 Found in 38ms (ActiveRecord: 0.0ms) Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 05:33:57 -0700 2013 Processing by ConsumerController#index as HTML Rendered consumer/index.html.erb within layouts/application (0.7ms) Completed 200 OK in 8ms (Views: 8.0ms | ActiveRecord: 0.0ms) Started GET "/assets/jquery.js?body=1" for 127.0.0.1 at Sun Mar 31 05:33:57 -0700 2013 Served asset /jquery.js - 304 Not Modified (0ms) Started GET "/assets/application.js?body=1" for 127.0.0.1 at Sun Mar 31 05:33:57 -0700 2013 Served asset /application.js - 304 Not Modified (0ms) Started GET "/assets/application.css?body=1" for 127.0.0.1 at Sun Mar 31 05:33:57 -0700 2013 Served asset /application.css - 304 Not Modified (0ms) Started GET "/consumer/start?openid_identifier=http%3A%2F%2Flocalhost%3A3009%2Fserver" for 127.0.0.1 at Sun Mar 31 05:34:12 -0700 2013 Processing by ConsumerController#start as HTML Parameters: {"openid_identifier"=>"http://localhost:3009/server"} Started GET "/server" for 127.0.0.1 at Sun Mar 31 05:34:12 -0700 2013 Processing by ServerController#index as application/xrds+xml Rendered text template (0.0ms) Completed 500 Internal Server Error in 5ms (Views: 1.9ms | ActiveRecord: 0.0ms) Redirected to http://localhost:3010/consumer Completed 302 Found in 20ms (ActiveRecord: 0.0ms) Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 05:34:13 -0700 2013 Processing by ConsumerController#index as HTML Rendered consumer/index.html.erb within layouts/application (0.6ms) Completed 200 OK in 11ms (Views: 10.2ms | ActiveRecord: 0.0ms) Started GET "/assets/application.css?body=1" for 127.0.0.1 at Sun Mar 31 05:34:13 -0700 2013 Served asset /application.css - 304 Not Modified (0ms) Started GET "/assets/jquery.js?body=1" for 127.0.0.1 at Sun Mar 31 05:34:13 -0700 2013 Served asset /jquery.js - 304 Not Modified (0ms) Started GET "/assets/application.js?body=1" for 127.0.0.1 at Sun Mar 31 05:34:13 -0700 2013 Served asset /application.js - 304 Not Modified (0ms) Started GET "/consumer/start?openid_identifier=http%3A%2F%2Flocalhost%3A3009%2Fserver%2Fidp_xrds" for 127.0.0.1 at Sun Mar 31 05:35:31 -0700 2013 Processing by ConsumerController#start as HTML Parameters: {"openid_identifier"=>"http://localhost:3009/server/idp_xrds"} Started GET "/server/idp_xrds" for 127.0.0.1 at Sun Mar 31 05:35:31 -0700 2013 Processing by ServerController#idp_xrds as application/xrds+xml Rendered text template (0.0ms) Completed 200 OK in 3ms (Views: 0.6ms | ActiveRecord: 0.0ms) Started POST "/server" for 127.0.0.1 at Sun Mar 31 05:35:32 -0700 2013 Processing by ServerController#index as */* Parameters: {"openid.mode"=>"associate", "openid.assoc_type"=>"HMAC-SHA1", "openid.session_type"=>"DH-SHA1", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.dh_consumer_public"=>"Ohd6vp/95+pq56SpKTaquSLrgWcVYQwVDbe+KsVnfn/bWAsT2TGS3v7AjwWKx5rfCZauIQ/c55uwMjT5iX5sAQFcNdOVtl5Ue42oFfkHDu01A7xovf2ZUdbw10m0Cl+g0BjDZRBagDShrlvBP3SZDMPvQu4o/04GhA6rChWnaGA="} WARNING: Can't verify CSRF token authenticity Rendered text template (0.0ms) Completed 200 OK in 40ms (Views: 0.7ms | ActiveRecord: 0.0ms) Redirected to http://localhost:3009/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete Completed 302 Found in 308ms (ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:35:32 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} Rendered server/decide.html.erb within layouts/server (1.2ms) Completed 200 OK in 21ms (Views: 5.0ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:37:07 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} Rendered server/decide.html.erb within layouts/server (2.1ms) Completed 200 OK in 18ms (Views: 5.0ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:37:10 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} Rendered server/decide.html.erb within layouts/server (1.1ms) Completed 200 OK in 16ms (Views: 4.4ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:38:02 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} Rendering decide template! Rendered server/decide.html.erb within layouts/server (1.0ms) Completed 200 OK in 15ms (Views: 8.3ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:38:11 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} Rendering decide template! Rendered server/decide.html.erb within layouts/server (1.2ms) Completed 200 OK in 18ms (Views: 14.0ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:39:23 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} Rendering decide template! Rendered server/decide.html.erb within layouts/server (1.1ms) Completed 200 OK in 8ms (Views: 5.0ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:39:26 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.6ms) Completed 200 OK in 11ms (Views: 4.1ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 05:39:52 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>"http://localhost:3009/marcel"} WARNING: Can't verify CSRF token authenticity Completed 500 Internal Server Error in 1ms NoMethodError (undefined method `identity' for nil:NilClass): app/controllers/server_controller.rb:143:in `decision' Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.7ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (1.4ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (15.5ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 05:41:02 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>"http://localhost:3009/marcel"} WARNING: Can't verify CSRF token authenticity Completed 500 Internal Server Error in 1ms NoMethodError (undefined method `identity' for nil:NilClass): app/controllers/server_controller.rb:143:in `decision' Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.9ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (1.2ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (14.4ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 05:41:56 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>"http://localhost:3009/marcel"} WARNING: Can't verify CSRF token authenticity Rendered text template (0.0ms) Completed 200 OK in 2ms (Views: 1.3ms | ActiveRecord: 0.0ms) Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 05:42:11 -0700 2013 Processing by ConsumerController#index as HTML Rendered consumer/index.html.erb within layouts/application (0.8ms) Completed 200 OK in 12ms (Views: 10.9ms | ActiveRecord: 0.0ms) Started GET "/assets/jquery.js?body=1" for 127.0.0.1 at Sun Mar 31 05:42:12 -0700 2013 Served asset /jquery.js - 304 Not Modified (0ms) Started GET "/assets/application.js?body=1" for 127.0.0.1 at Sun Mar 31 05:42:12 -0700 2013 Served asset /application.js - 304 Not Modified (0ms) Started GET "/assets/application.css?body=1" for 127.0.0.1 at Sun Mar 31 05:42:12 -0700 2013 Served asset /application.css - 304 Not Modified (0ms) Started GET "/consumer/start?openid_identifier=http%3A%2F%2Flocalhost%3A3009%2Fserver%2Fidp_xrds" for 127.0.0.1 at Sun Mar 31 05:42:28 -0700 2013 Processing by ConsumerController#start as HTML Parameters: {"openid_identifier"=>"http://localhost:3009/server/idp_xrds"} Started GET "/server/idp_xrds" for 127.0.0.1 at Sun Mar 31 05:42:28 -0700 2013 Processing by ServerController#idp_xrds as application/xrds+xml Rendered text template (0.0ms) Completed 200 OK in 1ms (Views: 0.5ms | ActiveRecord: 0.0ms) Redirected to http://localhost:3009/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete Completed 302 Found in 31ms (ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:42:28 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.6ms) Completed 200 OK in 8ms (Views: 3.8ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 05:42:36 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>"http://localhost:3009/marcel"} WARNING: Can't verify CSRF token authenticity Rendered text template (0.0ms) Completed 200 OK in 1ms (Views: 0.5ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:45:38 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.6ms) Completed 200 OK in 19ms (Views: 10.1ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:46:02 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.6ms) Completed 200 OK in 7ms (Views: 3.7ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:46:33 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.5ms) session: Rendering decide template! Completed 500 Internal Server Error in 10ms AbstractController::DoubleRenderError (Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like "redirect_to(...) and return".): app/controllers/server_controller.rb:88:in `show_decision_page' app/controllers/server_controller.rb:45:in `index' Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_trace.erb (2.2ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (5.0ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (25.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:46:47 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.6ms) session: Completed 200 OK in 8ms (Views: 4.8ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:48:24 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (1.3ms) session: Completed 200 OK in 15ms (Views: 11.0ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 05:48:44 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>"http://localhost:3009/marcel"} WARNING: Can't verify CSRF token authenticity last_oidreq: Rendered text template (0.0ms) Completed 200 OK in 1ms (Views: 0.6ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:54:41 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (1.6ms) session: session size: 804 Completed 200 OK in 14ms (Views: 5.4ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:54:59 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.6ms) session: Completed 500 Internal Server Error in 12ms TypeError (can't dump anonymous module #): app/controllers/server_controller.rb:45:in `dump' app/controllers/server_controller.rb:45:in `index' Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.9ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (3.6ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (27.3ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:56:19 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.6ms) session last_oidreq: session last_oidreq size: 804 Completed 200 OK in 8ms (Views: 4.3ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 05:56:21 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>""} WARNING: Can't verify CSRF token authenticity hello: last_oidreq: Rendered text template (0.0ms) Completed 200 OK in 1ms (Views: 0.5ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 05:56:26 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>""} WARNING: Can't verify CSRF token authenticity hello: last_oidreq: Rendered text template (0.0ms) Completed 200 OK in 1ms (Views: 0.5ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:56:36 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.6ms) session last_oidreq: session last_oidreq size: 804 Completed 200 OK in 8ms (Views: 3.7ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:56:37 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.5ms) session last_oidreq: session last_oidreq size: 804 Completed 200 OK in 7ms (Views: 3.1ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 05:56:44 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>""} WARNING: Can't verify CSRF token authenticity hello: last_oidreq: Rendered text template (0.0ms) Completed 200 OK in 1ms (Views: 0.8ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 05:57:14 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>""} WARNING: Can't verify CSRF token authenticity session_id: hello: last_oidreq: Rendered text template (0.0ms) Completed 200 OK in 2ms (Views: 1.4ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 05:57:35 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>""} WARNING: Can't verify CSRF token authenticity session_id: hello: last_oidreq: Rendered text template (0.0ms) Completed 200 OK in 3ms (Views: 2.1ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 05:58:17 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>""} WARNING: Can't verify CSRF token authenticity session_id: hello: last_oidreq: Rendered text template (0.0ms) Completed 200 OK in 2ms (Views: 1.3ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 05:59:23 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.6ms) session last_oidreq: session last_oidreq size: 804 session_id: 0df6cf9c44f69c6a4ab15e8a889cdbfc Completed 200 OK in 8ms (Views: 3.6ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 06:00:27 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.6ms) session last_oidreq: session last_oidreq size: 804 session_id: 0df6cf9c44f69c6a4ab15e8a889cdbfc session_id cookie: Completed 200 OK in 8ms (Views: 4.4ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 06:00:46 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.9ms) session last_oidreq: session last_oidreq size: 804 session_id: 0df6cf9c44f69c6a4ab15e8a889cdbfc session_id cookie: BAh7CSIPc2Vzc2lvbl9pZCIlMGRmNmNmOWM0NGY2OWM2YTRhYjE1ZThhODg5Y2RiZmMiCmhlbGxvIgp3b3JsZCIKZmxhc2hvOiVBY3Rpb25EaXNwYXRjaDo6Rmxhc2g6OkZsYXNoSGFzaAk6DUBmbGFzaGVzewY6C25vdGljZSIvRG8geW91IHRydXN0IHRoaXMgc2l0ZSB3aXRoIHlvdXIgaWRlbnRpdHk/OgpAdXNlZG86CFNldAY6CkBoYXNoewA6DEBjbG9zZWRGOglAbm93MCIQbGFzdF9vaWRyZXFvOiNPcGVuSUQ6OlNlcnZlcjo6Q2hlY2tJRFJlcXVlc3QOOhBAdHJ1c3Rfcm9vdCIjaHR0cDovL2xvY2FsaG9zdDozMDEwL2NvbnN1bWVyOg9AcmV0dXJuX3RvIixodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXIvY29tcGxldGU6DUBtZXNzYWdlbzoUT3BlbklEOjpNZXNzYWdlCDoQQG5hbWVzcGFjZXNvOhlPcGVuSUQ6Ok5hbWVzcGFjZU1hcAg6GEBhbGlhc190b19uYW1lc3BhY2V7BjoTbnVsbF9uYW1lc3BhY2UiJWh0dHA6Ly9zcGVjcy5vcGVuaWQubmV0L2F1dGgvMi4wOhlAaW1wbGljaXRfbmFtZXNwYWNlc1sAOhhAbmFtZXNwYWNlX3RvX2FsaWFzewYiJWh0dHA6Ly9zcGVjcy5vcGVuaWQubmV0L2F1dGgvMi4wOxU6E0BvcGVuaWRfbnNfdXJpQBc6CkBhcmdzew1bB0AXIgltb2RlIhJjaGVja2lkX3NldHVwWwdAFyIPY2xhaW1lZF9pZCI3aHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjAvaWRlbnRpZmllcl9zZWxlY3RbBzoTYmFyZV9uYW1lc3BhY2UiC2FjdGlvbiIKaW5kZXhbBzsaIg9jb250cm9sbGVyIgtzZXJ2ZXJbB0AXIhFhc3NvY19oYW5kbGUiJHtITUFDLVNIQTF9ezUxNTgyZDk0fXtjZGtvMWc9PX1bB0AXIg5yZXR1cm5fdG9AE1sHQBciCnJlYWxtQBJbB0AXIg1pZGVudGl0eSI3aHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjAvaWRlbnRpZmllcl9zZWxlY3Q6D0BpbW1lZGlhdGVGOg5AaWRlbnRpdHlAMToSQGFzc29jX2hhbmRsZUAqOhBAY2xhaW1lZF9pZEAhOgpAbW9kZSISY2hlY2tpZF9zZXR1cDoRQG9wX2VuZHBvaW50IiFodHRwOi8vbG9jYWxob3N0OjMwMDkvc2VydmVy--e9977c9d345b7da60a35bbd6b27618a288f54057 Completed 200 OK in 31ms (Views: 14.7ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 06:01:27 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>""} WARNING: Can't verify CSRF token authenticity session_id: session_id cookie: BAh7CSIPc2Vzc2lvbl9pZCIlMGRmNmNmOWM0NGY2OWM2YTRhYjE1ZThhODg5Y2RiZmMiCmhlbGxvIgp3b3JsZCIQbGFzdF9vaWRyZXFvOiNPcGVuSUQ6OlNlcnZlcjo6Q2hlY2tJRFJlcXVlc3QOOhBAdHJ1c3Rfcm9vdCIjaHR0cDovL2xvY2FsaG9zdDozMDEwL2NvbnN1bWVyOg9AcmV0dXJuX3RvIixodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXIvY29tcGxldGU6DUBtZXNzYWdlbzoUT3BlbklEOjpNZXNzYWdlCDoQQG5hbWVzcGFjZXNvOhlPcGVuSUQ6Ok5hbWVzcGFjZU1hcAg6GEBhbGlhc190b19uYW1lc3BhY2V7BjoTbnVsbF9uYW1lc3BhY2UiJWh0dHA6Ly9zcGVjcy5vcGVuaWQubmV0L2F1dGgvMi4wOhlAaW1wbGljaXRfbmFtZXNwYWNlc1sAOhhAbmFtZXNwYWNlX3RvX2FsaWFzewYiJWh0dHA6Ly9zcGVjcy5vcGVuaWQubmV0L2F1dGgvMi4wOw06E0BvcGVuaWRfbnNfdXJpQBE6CkBhcmdzew1bB0ARIgltb2RlIhJjaGVja2lkX3NldHVwWwdAESIPY2xhaW1lZF9pZCI3aHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjAvaWRlbnRpZmllcl9zZWxlY3RbBzoTYmFyZV9uYW1lc3BhY2UiC2FjdGlvbiIKaW5kZXhbBzsSIg9jb250cm9sbGVyIgtzZXJ2ZXJbB0ARIhFhc3NvY19oYW5kbGUiJHtITUFDLVNIQTF9ezUxNTgyZDk0fXtjZGtvMWc9PX1bB0ARIg5yZXR1cm5fdG9ADVsHQBEiCnJlYWxtQAxbB0ARIg1pZGVudGl0eSI3aHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjAvaWRlbnRpZmllcl9zZWxlY3Q6D0BpbW1lZGlhdGVGOg5AaWRlbnRpdHlAKzoSQGFzc29jX2hhbmRsZUAkOhBAY2xhaW1lZF9pZEAbOgpAbW9kZSISY2hlY2tpZF9zZXR1cDoRQG9wX2VuZHBvaW50IiFodHRwOi8vbG9jYWxob3N0OjMwMDkvc2VydmVyIgpmbGFzaG86JUFjdGlvbkRpc3BhdGNoOjpGbGFzaDo6Rmxhc2hIYXNoCToNQGZsYXNoZXN7BjoLbm90aWNlIi9EbyB5b3UgdHJ1c3QgdGhpcyBzaXRlIHdpdGggeW91ciBpZGVudGl0eT86CkB1c2VkbzoIU2V0BjoKQGhhc2h7ADoMQGNsb3NlZEY6CUBub3cw--097664684a5b4ec726b2e9621c60066bdffa2b08 hello: last_oidreq: Rendered text template (0.0ms) Completed 200 OK in 2ms (Views: 1.2ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 06:01:46 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>""} WARNING: Can't verify CSRF token authenticity session_id: session_id cookie: BAh7BzoQbGFzdF9vaWRyZXEwIg9zZXNzaW9uX2lkIiViMjkzOWYzZGM1MGUzZGVhN2MzMjQwODgwMzk4ZDRlZg==--5c9b11469badcabaca82548d4d506f6b7b1e834f hello: last_oidreq: Rendered text template (0.0ms) Completed 200 OK in 2ms (Views: 1.2ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 06:07:21 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (1.2ms) session last_oidreq: session last_oidreq size: 804 session_id: d50d3dd624bc8ca8e44f1203c96a8f93 session_id cookie: BAh7BzoQbGFzdF9vaWRyZXEwIg9zZXNzaW9uX2lkIiVkNTBkM2RkNjI0YmM4Y2E4ZTQ0ZjEyMDNjOTZhOGY5Mw==--4184fd96c6f41491285b5f6c1e96b4b72e28c2f8 Completed 200 OK in 10ms (Views: 4.6ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 06:07:33 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (157.0ms) Completed 500 Internal Server Error in 166ms ActionView::Template::Error (undefined local variable or method `form_authenticity_token_field' for #<#:0x10358a698>): 1:
2: <%= form_authenticity_token_field %> 3: 4: 5: app/views/server/decide.html.erb:2:in `_app_views_server_decide_html_erb___1096845836_2175551400' app/controllers/server_controller.rb:92:in `show_decision_page' app/controllers/server_controller.rb:43:in `index' Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.8ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (2.3ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/template_error.erb within rescues/layout (15.6ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 06:09:13 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (42.6ms) Completed 500 Internal Server Error in 49ms ActionView::Template::Error (undefined local variable or method `form_authenticity_param' for #<#:0x103920618>): 1: 2: 3: 4:
Site:<%= @oidreq.trust_root %>
5: app/views/server/decide.html.erb:2:in `_app_views_server_decide_html_erb___1096845836_2177422820' app/controllers/server_controller.rb:92:in `show_decision_page' app/controllers/server_controller.rb:43:in `index' Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_trace.erb (3.1ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (1.6ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/template_error.erb within rescues/layout (20.9ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 06:10:58 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (1.0ms) session last_oidreq: session last_oidreq size: 804 session_id: d50d3dd624bc8ca8e44f1203c96a8f93 session_id cookie: BAh7CiIQX2NzcmZfdG9rZW4iMTVIMWQ0bEVzMnA4Qjd0enZHTXNIZXRLOUtPcTZCbFl4UFN6dyt2SFJTckE9Ig9zZXNzaW9uX2lkIiVkNTBkM2RkNjI0YmM4Y2E4ZTQ0ZjEyMDNjOTZhOGY5MyIKaGVsbG8iCndvcmxkIhBsYXN0X29pZHJlcW86I09wZW5JRDo6U2VydmVyOjpDaGVja0lEUmVxdWVzdA46EEB0cnVzdF9yb290IiNodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXI6D0ByZXR1cm5fdG8iLGh0dHA6Ly9sb2NhbGhvc3Q6MzAxMC9jb25zdW1lci9jb21wbGV0ZToNQG1lc3NhZ2VvOhRPcGVuSUQ6Ok1lc3NhZ2UIOhBAbmFtZXNwYWNlc286GU9wZW5JRDo6TmFtZXNwYWNlTWFwCDoYQGFsaWFzX3RvX25hbWVzcGFjZXsGOhNudWxsX25hbWVzcGFjZSIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA6GUBpbXBsaWNpdF9uYW1lc3BhY2VzWwA6GEBuYW1lc3BhY2VfdG9fYWxpYXN7BiIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA7DToTQG9wZW5pZF9uc191cmlAEzoKQGFyZ3N7DVsHQBMiCW1vZGUiEmNoZWNraWRfc2V0dXBbB0ATIg9jbGFpbWVkX2lkIjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdFsHOhNiYXJlX25hbWVzcGFjZSILYWN0aW9uIgppbmRleFsHOxIiD2NvbnRyb2xsZXIiC3NlcnZlclsHQBMiEWFzc29jX2hhbmRsZSIke0hNQUMtU0hBMX17NTE1ODJkOTR9e2Nka28xZz09fVsHQBMiDnJldHVybl90b0APWwdAEyIKcmVhbG1ADlsHQBMiDWlkZW50aXR5IjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdDoPQGltbWVkaWF0ZUY6DkBpZGVudGl0eUAtOhJAYXNzb2NfaGFuZGxlQCY6EEBjbGFpbWVkX2lkQB06CkBtb2RlIhJjaGVja2lkX3NldHVwOhFAb3BfZW5kcG9pbnQiIWh0dHA6Ly9sb2NhbGhvc3Q6MzAwOS9zZXJ2ZXIiCmZsYXNobzolQWN0aW9uRGlzcGF0Y2g6OkZsYXNoOjpGbGFzaEhhc2gJOg1AZmxhc2hlc3sGOgtub3RpY2UiL0RvIHlvdSB0cnVzdCB0aGlzIHNpdGUgd2l0aCB5b3VyIGlkZW50aXR5PzoKQHVzZWRvOghTZXQGOgpAaGFzaHsAOgxAY2xvc2VkRjoJQG5vdzA=--0b12a84d3b56c065d035566362e3e9374de86039 Completed 200 OK in 8ms (Views: 4.8ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 06:11:00 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>""} WARNING: Can't verify CSRF token authenticity session_id: session_id cookie: BAh7CiIQX2NzcmZfdG9rZW4iMTVIMWQ0bEVzMnA4Qjd0enZHTXNIZXRLOUtPcTZCbFl4UFN6dyt2SFJTckE9Ig9zZXNzaW9uX2lkIiVkNTBkM2RkNjI0YmM4Y2E4ZTQ0ZjEyMDNjOTZhOGY5MyIKaGVsbG8iCndvcmxkIgpmbGFzaG86JUFjdGlvbkRpc3BhdGNoOjpGbGFzaDo6Rmxhc2hIYXNoCToNQGZsYXNoZXN7BjoLbm90aWNlIi9EbyB5b3UgdHJ1c3QgdGhpcyBzaXRlIHdpdGggeW91ciBpZGVudGl0eT86CkB1c2VkbzoIU2V0BjoKQGhhc2h7ADoMQGNsb3NlZEY6CUBub3cwIhBsYXN0X29pZHJlcW86I09wZW5JRDo6U2VydmVyOjpDaGVja0lEUmVxdWVzdA46EEB0cnVzdF9yb290IiNodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXI6D0ByZXR1cm5fdG8iLGh0dHA6Ly9sb2NhbGhvc3Q6MzAxMC9jb25zdW1lci9jb21wbGV0ZToNQG1lc3NhZ2VvOhRPcGVuSUQ6Ok1lc3NhZ2UIOhBAbmFtZXNwYWNlc286GU9wZW5JRDo6TmFtZXNwYWNlTWFwCDoYQGFsaWFzX3RvX25hbWVzcGFjZXsGOhNudWxsX25hbWVzcGFjZSIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA6GUBpbXBsaWNpdF9uYW1lc3BhY2VzWwA6GEBuYW1lc3BhY2VfdG9fYWxpYXN7BiIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA7FToTQG9wZW5pZF9uc191cmlAGToKQGFyZ3N7DVsHQBkiCW1vZGUiEmNoZWNraWRfc2V0dXBbB0AZIg9jbGFpbWVkX2lkIjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdFsHOhNiYXJlX25hbWVzcGFjZSILYWN0aW9uIgppbmRleFsHOxoiD2NvbnRyb2xsZXIiC3NlcnZlclsHQBkiEWFzc29jX2hhbmRsZSIke0hNQUMtU0hBMX17NTE1ODJkOTR9e2Nka28xZz09fVsHQBkiDnJldHVybl90b0AVWwdAGSIKcmVhbG1AFFsHQBkiDWlkZW50aXR5IjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdDoPQGltbWVkaWF0ZUY6DkBpZGVudGl0eUAzOhJAYXNzb2NfaGFuZGxlQCw6EEBjbGFpbWVkX2lkQCM6CkBtb2RlIhJjaGVja2lkX3NldHVwOhFAb3BfZW5kcG9pbnQiIWh0dHA6Ly9sb2NhbGhvc3Q6MzAwOS9zZXJ2ZXI=--efe18d78f0dd5ccfbb16f8706b35781d95ffead8 hello: last_oidreq: Rendered text template (0.0ms) Completed 200 OK in 1ms (Views: 0.6ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 06:11:03 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.6ms) session last_oidreq: session last_oidreq size: 804 session_id: b0111bc499a041f6669c0cffd50c4854 session_id cookie: BAh7BzoQbGFzdF9vaWRyZXEwIg9zZXNzaW9uX2lkIiViMDExMWJjNDk5YTA0MWY2NjY5YzBjZmZkNTBjNDg1NA==--73c5bfc2bb790437f2b141aaf0c20cd6cc426da7 Completed 200 OK in 9ms (Views: 3.5ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 06:11:05 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.8ms) session last_oidreq: session last_oidreq size: 804 session_id: b0111bc499a041f6669c0cffd50c4854 session_id cookie: BAh7CiIQX2NzcmZfdG9rZW4iMURlelQzMjdHQk9aRUdxakRaM2pjeTFjY3ZsRmN0eHJQdUF2UGJLWUg3WTA9Ig9zZXNzaW9uX2lkIiViMDExMWJjNDk5YTA0MWY2NjY5YzBjZmZkNTBjNDg1NCIKaGVsbG8iCndvcmxkIhBsYXN0X29pZHJlcW86I09wZW5JRDo6U2VydmVyOjpDaGVja0lEUmVxdWVzdA46EEB0cnVzdF9yb290IiNodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXI6D0ByZXR1cm5fdG8iLGh0dHA6Ly9sb2NhbGhvc3Q6MzAxMC9jb25zdW1lci9jb21wbGV0ZToNQG1lc3NhZ2VvOhRPcGVuSUQ6Ok1lc3NhZ2UIOhBAbmFtZXNwYWNlc286GU9wZW5JRDo6TmFtZXNwYWNlTWFwCDoYQGFsaWFzX3RvX25hbWVzcGFjZXsGOhNudWxsX25hbWVzcGFjZSIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA6GUBpbXBsaWNpdF9uYW1lc3BhY2VzWwA6GEBuYW1lc3BhY2VfdG9fYWxpYXN7BiIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA7DToTQG9wZW5pZF9uc191cmlAEzoKQGFyZ3N7DVsHQBMiCW1vZGUiEmNoZWNraWRfc2V0dXBbB0ATIg9jbGFpbWVkX2lkIjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdFsHOhNiYXJlX25hbWVzcGFjZSILYWN0aW9uIgppbmRleFsHOxIiD2NvbnRyb2xsZXIiC3NlcnZlclsHQBMiEWFzc29jX2hhbmRsZSIke0hNQUMtU0hBMX17NTE1ODJkOTR9e2Nka28xZz09fVsHQBMiDnJldHVybl90b0APWwdAEyIKcmVhbG1ADlsHQBMiDWlkZW50aXR5IjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdDoPQGltbWVkaWF0ZUY6DkBpZGVudGl0eUAtOhJAYXNzb2NfaGFuZGxlQCY6EEBjbGFpbWVkX2lkQB06CkBtb2RlIhJjaGVja2lkX3NldHVwOhFAb3BfZW5kcG9pbnQiIWh0dHA6Ly9sb2NhbGhvc3Q6MzAwOS9zZXJ2ZXIiCmZsYXNobzolQWN0aW9uRGlzcGF0Y2g6OkZsYXNoOjpGbGFzaEhhc2gJOg1AZmxhc2hlc3sGOgtub3RpY2UiL0RvIHlvdSB0cnVzdCB0aGlzIHNpdGUgd2l0aCB5b3VyIGlkZW50aXR5PzoKQHVzZWRvOghTZXQGOgpAaGFzaHsAOgxAY2xvc2VkRjoJQG5vdzA=--4aa0ecdd65e5219704711e40c58139be1348db1f Completed 200 OK in 10ms (Views: 5.1ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 06:11:06 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>""} WARNING: Can't verify CSRF token authenticity session_id: session_id cookie: BAh7CiIQX2NzcmZfdG9rZW4iMURlelQzMjdHQk9aRUdxakRaM2pjeTFjY3ZsRmN0eHJQdUF2UGJLWUg3WTA9Ig9zZXNzaW9uX2lkIiViMDExMWJjNDk5YTA0MWY2NjY5YzBjZmZkNTBjNDg1NCIKaGVsbG8iCndvcmxkIgpmbGFzaG86JUFjdGlvbkRpc3BhdGNoOjpGbGFzaDo6Rmxhc2hIYXNoCToNQGZsYXNoZXN7BjoLbm90aWNlIi9EbyB5b3UgdHJ1c3QgdGhpcyBzaXRlIHdpdGggeW91ciBpZGVudGl0eT86CkB1c2VkbzoIU2V0BjoKQGhhc2h7ADoMQGNsb3NlZEY6CUBub3cwIhBsYXN0X29pZHJlcW86I09wZW5JRDo6U2VydmVyOjpDaGVja0lEUmVxdWVzdA46EEB0cnVzdF9yb290IiNodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXI6D0ByZXR1cm5fdG8iLGh0dHA6Ly9sb2NhbGhvc3Q6MzAxMC9jb25zdW1lci9jb21wbGV0ZToNQG1lc3NhZ2VvOhRPcGVuSUQ6Ok1lc3NhZ2UIOhBAbmFtZXNwYWNlc286GU9wZW5JRDo6TmFtZXNwYWNlTWFwCDoYQGFsaWFzX3RvX25hbWVzcGFjZXsGOhNudWxsX25hbWVzcGFjZSIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA6GUBpbXBsaWNpdF9uYW1lc3BhY2VzWwA6GEBuYW1lc3BhY2VfdG9fYWxpYXN7BiIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA7FToTQG9wZW5pZF9uc191cmlAGToKQGFyZ3N7DVsHQBkiCW1vZGUiEmNoZWNraWRfc2V0dXBbB0AZIg9jbGFpbWVkX2lkIjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdFsHOhNiYXJlX25hbWVzcGFjZSILYWN0aW9uIgppbmRleFsHOxoiD2NvbnRyb2xsZXIiC3NlcnZlclsHQBkiEWFzc29jX2hhbmRsZSIke0hNQUMtU0hBMX17NTE1ODJkOTR9e2Nka28xZz09fVsHQBkiDnJldHVybl90b0AVWwdAGSIKcmVhbG1AFFsHQBkiDWlkZW50aXR5IjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdDoPQGltbWVkaWF0ZUY6DkBpZGVudGl0eUAzOhJAYXNzb2NfaGFuZGxlQCw6EEBjbGFpbWVkX2lkQCM6CkBtb2RlIhJjaGVja2lkX3NldHVwOhFAb3BfZW5kcG9pbnQiIWh0dHA6Ly9sb2NhbGhvc3Q6MzAwOS9zZXJ2ZXI=--2e2b7c25a4b12809bc26063679446f2ea9bb0c95 hello: last_oidreq: Rendered text template (0.0ms) Completed 200 OK in 2ms (Views: 0.6ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 06:11:40 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>""} WARNING: Can't verify CSRF token authenticity session_id: session_id cookie: BAh7BzoQbGFzdF9vaWRyZXEwIg9zZXNzaW9uX2lkIiVkZTEzMjgwMDA5ZGU5NGQ1NjkzYWExNjUxNDFmMWYyNQ==--fb03aa366527aebbe8dd7fd9a6be3905ea7690b6 hello: last_oidreq: Rendered text template (0.0ms) Completed 200 OK in 4ms (Views: 1.6ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 06:11:42 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.6ms) session last_oidreq: session last_oidreq size: 804 session_id: 396fcb58d8777c7f869bf8084e96482c session_id cookie: BAh7BzoQbGFzdF9vaWRyZXEwIg9zZXNzaW9uX2lkIiUzOTZmY2I1OGQ4Nzc3YzdmODY5YmY4MDg0ZTk2NDgyYw==--48268edfcda33e221ff56a92f7c2cc30efd4951a Completed 200 OK in 14ms (Views: 5.4ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 06:11:43 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"yes"=>"yes", "id_to_send"=>""} WARNING: Can't verify CSRF token authenticity session_id: session_id cookie: BAh7CiIQX2NzcmZfdG9rZW4iMVBONjA1NXlibkNzaWJEZ1pTZ0k5KzEwZStoVXdRZUpPYU5FYzRlL3J0MW89Ig9zZXNzaW9uX2lkIiUzOTZmY2I1OGQ4Nzc3YzdmODY5YmY4MDg0ZTk2NDgyYyIKaGVsbG8iCndvcmxkIhBsYXN0X29pZHJlcW86I09wZW5JRDo6U2VydmVyOjpDaGVja0lEUmVxdWVzdA46EEB0cnVzdF9yb290IiNodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXI6D0ByZXR1cm5fdG8iLGh0dHA6Ly9sb2NhbGhvc3Q6MzAxMC9jb25zdW1lci9jb21wbGV0ZToNQG1lc3NhZ2VvOhRPcGVuSUQ6Ok1lc3NhZ2UIOhBAbmFtZXNwYWNlc286GU9wZW5JRDo6TmFtZXNwYWNlTWFwCDoYQGFsaWFzX3RvX25hbWVzcGFjZXsGOhNudWxsX25hbWVzcGFjZSIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA6GUBpbXBsaWNpdF9uYW1lc3BhY2VzWwA6GEBuYW1lc3BhY2VfdG9fYWxpYXN7BiIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA7DToTQG9wZW5pZF9uc191cmlAEzoKQGFyZ3N7DVsHQBMiCW1vZGUiEmNoZWNraWRfc2V0dXBbB0ATIg9jbGFpbWVkX2lkIjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdFsHOhNiYXJlX25hbWVzcGFjZSILYWN0aW9uIgppbmRleFsHOxIiD2NvbnRyb2xsZXIiC3NlcnZlclsHQBMiEWFzc29jX2hhbmRsZSIke0hNQUMtU0hBMX17NTE1ODJkOTR9e2Nka28xZz09fVsHQBMiDnJldHVybl90b0APWwdAEyIKcmVhbG1ADlsHQBMiDWlkZW50aXR5IjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdDoPQGltbWVkaWF0ZUY6DkBpZGVudGl0eUAtOhJAYXNzb2NfaGFuZGxlQCY6EEBjbGFpbWVkX2lkQB06CkBtb2RlIhJjaGVja2lkX3NldHVwOhFAb3BfZW5kcG9pbnQiIWh0dHA6Ly9sb2NhbGhvc3Q6MzAwOS9zZXJ2ZXIiCmZsYXNobzolQWN0aW9uRGlzcGF0Y2g6OkZsYXNoOjpGbGFzaEhhc2gJOg1AZmxhc2hlc3sGOgtub3RpY2UiL0RvIHlvdSB0cnVzdCB0aGlzIHNpdGUgd2l0aCB5b3VyIGlkZW50aXR5PzoKQHVzZWRvOghTZXQGOgpAaGFzaHsAOgxAY2xvc2VkRjoJQG5vdzA=--9d8e44ba14ab5c85a086e860ea1481f71067e88f hello: last_oidreq: Rendered text template (0.0ms) Completed 200 OK in 1ms (Views: 0.6ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 06:12:51 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (1.0ms) session last_oidreq: session last_oidreq size: 804 session_id: 2c66ed926ccfe2103c298469eb4818f8 session_id cookie: BAh7BzoQbGFzdF9vaWRyZXEwIg9zZXNzaW9uX2lkIiUyYzY2ZWQ5MjZjY2ZlMjEwM2MyOTg0NjllYjQ4MThmOA==--6457aa16715de946fb9167e165af7f022d49cd5f Completed 200 OK in 7ms (Views: 3.8ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 06:12:53 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"_token"=>"rLGwlRuk0Zz/nS165br3PrN5Zre3xpwKpSsHGDqntog=", "yes"=>"yes", "id_to_send"=>""} WARNING: Can't verify CSRF token authenticity session_id: session_id cookie: BAh7CiIQX2NzcmZfdG9rZW4iMXJMR3dsUnVrMFp6L25TMTY1YnIzUHJONVpyZTN4cHdLcFNzSEdEcW50b2c9Ig9zZXNzaW9uX2lkIiUyYzY2ZWQ5MjZjY2ZlMjEwM2MyOTg0NjllYjQ4MThmOCIKaGVsbG8iCndvcmxkIhBsYXN0X29pZHJlcW86I09wZW5JRDo6U2VydmVyOjpDaGVja0lEUmVxdWVzdA46EEB0cnVzdF9yb290IiNodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXI6D0ByZXR1cm5fdG8iLGh0dHA6Ly9sb2NhbGhvc3Q6MzAxMC9jb25zdW1lci9jb21wbGV0ZToNQG1lc3NhZ2VvOhRPcGVuSUQ6Ok1lc3NhZ2UIOhBAbmFtZXNwYWNlc286GU9wZW5JRDo6TmFtZXNwYWNlTWFwCDoYQGFsaWFzX3RvX25hbWVzcGFjZXsGOhNudWxsX25hbWVzcGFjZSIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA6GUBpbXBsaWNpdF9uYW1lc3BhY2VzWwA6GEBuYW1lc3BhY2VfdG9fYWxpYXN7BiIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA7DToTQG9wZW5pZF9uc191cmlAEzoKQGFyZ3N7DVsHQBMiCW1vZGUiEmNoZWNraWRfc2V0dXBbB0ATIg9jbGFpbWVkX2lkIjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdFsHOhNiYXJlX25hbWVzcGFjZSILYWN0aW9uIgppbmRleFsHOxIiD2NvbnRyb2xsZXIiC3NlcnZlclsHQBMiEWFzc29jX2hhbmRsZSIke0hNQUMtU0hBMX17NTE1ODJkOTR9e2Nka28xZz09fVsHQBMiDnJldHVybl90b0APWwdAEyIKcmVhbG1ADlsHQBMiDWlkZW50aXR5IjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdDoPQGltbWVkaWF0ZUY6DkBpZGVudGl0eUAtOhJAYXNzb2NfaGFuZGxlQCY6EEBjbGFpbWVkX2lkQB06CkBtb2RlIhJjaGVja2lkX3NldHVwOhFAb3BfZW5kcG9pbnQiIWh0dHA6Ly9sb2NhbGhvc3Q6MzAwOS9zZXJ2ZXIiCmZsYXNobzolQWN0aW9uRGlzcGF0Y2g6OkZsYXNoOjpGbGFzaEhhc2gJOg1AZmxhc2hlc3sGOgtub3RpY2UiL0RvIHlvdSB0cnVzdCB0aGlzIHNpdGUgd2l0aCB5b3VyIGlkZW50aXR5PzoKQHVzZWRvOghTZXQGOgpAaGFzaHsAOgxAY2xvc2VkRjoJQG5vdzA=--f8ed02db84ccf0f80fc1bd2f0f4095cbc249caac hello: last_oidreq: Rendered text template (0.0ms) Completed 200 OK in 2ms (Views: 0.9ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 06:15:54 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (1.7ms) session last_oidreq: session last_oidreq size: 804 session_id: ff4ab3c2833d6324f1fcc3a4de587fe1 session_id cookie: BAh7BzoQbGFzdF9vaWRyZXEwIg9zZXNzaW9uX2lkIiVmZjRhYjNjMjgzM2Q2MzI0ZjFmY2MzYTRkZTU4N2ZlMQ==--0b1f7487ae5567045e91d39d107132c75a1e1c59 Completed 200 OK in 45ms (Views: 40.8ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 06:15:55 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"authenticity_token"=>"jgWPOedLngI1CoE4miIBy3FprrZr/xYlHnBoTWn9fOc=", "yes"=>"yes", "id_to_send"=>""} session_id: ff4ab3c2833d6324f1fcc3a4de587fe1 session_id cookie: BAh7CiIQX2NzcmZfdG9rZW4iMWpnV1BPZWRMbmdJMUNvRTRtaUlCeTNGcHJyWnIveFlsSG5Cb1RXbjlmT2M9Ig9zZXNzaW9uX2lkIiVmZjRhYjNjMjgzM2Q2MzI0ZjFmY2MzYTRkZTU4N2ZlMSIKaGVsbG8iCndvcmxkIhBsYXN0X29pZHJlcW86I09wZW5JRDo6U2VydmVyOjpDaGVja0lEUmVxdWVzdA46EEB0cnVzdF9yb290IiNodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXI6D0ByZXR1cm5fdG8iLGh0dHA6Ly9sb2NhbGhvc3Q6MzAxMC9jb25zdW1lci9jb21wbGV0ZToNQG1lc3NhZ2VvOhRPcGVuSUQ6Ok1lc3NhZ2UIOhBAbmFtZXNwYWNlc286GU9wZW5JRDo6TmFtZXNwYWNlTWFwCDoYQGFsaWFzX3RvX25hbWVzcGFjZXsGOhNudWxsX25hbWVzcGFjZSIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA6GUBpbXBsaWNpdF9uYW1lc3BhY2VzWwA6GEBuYW1lc3BhY2VfdG9fYWxpYXN7BiIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA7DToTQG9wZW5pZF9uc191cmlAEzoKQGFyZ3N7DVsHQBMiCW1vZGUiEmNoZWNraWRfc2V0dXBbB0ATIg9jbGFpbWVkX2lkIjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdFsHOhNiYXJlX25hbWVzcGFjZSILYWN0aW9uIgppbmRleFsHOxIiD2NvbnRyb2xsZXIiC3NlcnZlclsHQBMiEWFzc29jX2hhbmRsZSIke0hNQUMtU0hBMX17NTE1ODJkOTR9e2Nka28xZz09fVsHQBMiDnJldHVybl90b0APWwdAEyIKcmVhbG1ADlsHQBMiDWlkZW50aXR5IjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdDoPQGltbWVkaWF0ZUY6DkBpZGVudGl0eUAtOhJAYXNzb2NfaGFuZGxlQCY6EEBjbGFpbWVkX2lkQB06CkBtb2RlIhJjaGVja2lkX3NldHVwOhFAb3BfZW5kcG9pbnQiIWh0dHA6Ly9sb2NhbGhvc3Q6MzAwOS9zZXJ2ZXIiCmZsYXNobzolQWN0aW9uRGlzcGF0Y2g6OkZsYXNoOjpGbGFzaEhhc2gJOg1AZmxhc2hlc3sGOgtub3RpY2UiL0RvIHlvdSB0cnVzdCB0aGlzIHNpdGUgd2l0aCB5b3VyIGlkZW50aXR5PzoKQHVzZWRvOghTZXQGOgpAaGFzaHsAOgxAY2xvc2VkRjoJQG5vdzA=--9a1ec542115a344418fdc5587685b73737444aef hello: world last_oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.7ms) Completed 200 OK in 5ms (Views: 4.4ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 06:15:58 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"authenticity_token"=>"jgWPOedLngI1CoE4miIBy3FprrZr/xYlHnBoTWn9fOc=", "yes"=>"yes", "id_to_send"=>""} session_id: ff4ab3c2833d6324f1fcc3a4de587fe1 session_id cookie: BAh7CiIQX2NzcmZfdG9rZW4iMWpnV1BPZWRMbmdJMUNvRTRtaUlCeTNGcHJyWnIveFlsSG5Cb1RXbjlmT2M9Ig9zZXNzaW9uX2lkIiVmZjRhYjNjMjgzM2Q2MzI0ZjFmY2MzYTRkZTU4N2ZlMSIKaGVsbG8iCndvcmxkIgpmbGFzaG86JUFjdGlvbkRpc3BhdGNoOjpGbGFzaDo6Rmxhc2hIYXNoCToNQGZsYXNoZXN7BjoLbm90aWNlIlZZb3UgbXVzdCBlbnRlciBhIHVzZXJuYW1lIHRvIGluIG9yZGVyIHRvIHNlbmQgYW4gaWRlbnRpZmllciB0byB0aGUgUmVseWluZyBQYXJ0eS46CkB1c2VkbzoIU2V0BjoKQGhhc2h7ADoMQGNsb3NlZEY6CUBub3cwIhBsYXN0X29pZHJlcW86I09wZW5JRDo6U2VydmVyOjpDaGVja0lEUmVxdWVzdA46EEB0cnVzdF9yb290IiNodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXI6D0ByZXR1cm5fdG8iLGh0dHA6Ly9sb2NhbGhvc3Q6MzAxMC9jb25zdW1lci9jb21wbGV0ZToNQG1lc3NhZ2VvOhRPcGVuSUQ6Ok1lc3NhZ2UIOhBAbmFtZXNwYWNlc286GU9wZW5JRDo6TmFtZXNwYWNlTWFwCDoYQGFsaWFzX3RvX25hbWVzcGFjZXsGOhNudWxsX25hbWVzcGFjZSIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA6GUBpbXBsaWNpdF9uYW1lc3BhY2VzWwA6GEBuYW1lc3BhY2VfdG9fYWxpYXN7BiIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA7FToKQGFyZ3N7DVsHOhNiYXJlX25hbWVzcGFjZSILYWN0aW9uIgppbmRleFsHQBkiD2NsYWltZWRfaWQiN2h0dHA6Ly9zcGVjcy5vcGVuaWQubmV0L2F1dGgvMi4wL2lkZW50aWZpZXJfc2VsZWN0WwdAGSIJbW9kZSISY2hlY2tpZF9zZXR1cFsHOxkiD2NvbnRyb2xsZXIiC3NlcnZlclsHQBkiDnJldHVybl90b0AVWwdAGSIRYXNzb2NfaGFuZGxlIiR7SE1BQy1TSEExfXs1MTU4MmQ5NH17Y2RrbzFnPT19WwdAGSINaWRlbnRpdHkiN2h0dHA6Ly9zcGVjcy5vcGVuaWQubmV0L2F1dGgvMi4wL2lkZW50aWZpZXJfc2VsZWN0WwdAGSIKcmVhbG1AFDoTQG9wZW5pZF9uc191cmlAGToPQGltbWVkaWF0ZUY6DkBpZGVudGl0eUAxOhJAYXNzb2NfaGFuZGxlQC46EUBvcF9lbmRwb2ludCIhaHR0cDovL2xvY2FsaG9zdDozMDA5L3NlcnZlcjoKQG1vZGUiEmNoZWNraWRfc2V0dXA6EEBjbGFpbWVkX2lkQCM=--d18faa6ccd17ce34ee9d7d0cc67cfa3b8e5589c1 hello: world last_oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.8ms) Completed 200 OK in 6ms (Views: 5.0ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 06:16:23 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"authenticity_token"=>"jgWPOedLngI1CoE4miIBy3FprrZr/xYlHnBoTWn9fOc=", "yes"=>"yes", "id_to_send"=>""} session_id: ff4ab3c2833d6324f1fcc3a4de587fe1 session_id cookie: BAh7CiIQX2NzcmZfdG9rZW4iMWpnV1BPZWRMbmdJMUNvRTRtaUlCeTNGcHJyWnIveFlsSG5Cb1RXbjlmT2M9Ig9zZXNzaW9uX2lkIiVmZjRhYjNjMjgzM2Q2MzI0ZjFmY2MzYTRkZTU4N2ZlMSIKaGVsbG8iCndvcmxkIhBsYXN0X29pZHJlcW86I09wZW5JRDo6U2VydmVyOjpDaGVja0lEUmVxdWVzdA46EEB0cnVzdF9yb290IiNodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXI6D0ByZXR1cm5fdG8iLGh0dHA6Ly9sb2NhbGhvc3Q6MzAxMC9jb25zdW1lci9jb21wbGV0ZToNQG1lc3NhZ2VvOhRPcGVuSUQ6Ok1lc3NhZ2UIOhBAbmFtZXNwYWNlc286GU9wZW5JRDo6TmFtZXNwYWNlTWFwCDoYQGFsaWFzX3RvX25hbWVzcGFjZXsGOhNudWxsX25hbWVzcGFjZSIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA6GUBpbXBsaWNpdF9uYW1lc3BhY2VzWwA6GEBuYW1lc3BhY2VfdG9fYWxpYXN7BiIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA7DToTQG9wZW5pZF9uc191cmlAEzoKQGFyZ3N7DVsHQBMiCW1vZGUiEmNoZWNraWRfc2V0dXBbB0ATIg9jbGFpbWVkX2lkIjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdFsHOhNiYXJlX25hbWVzcGFjZSILYWN0aW9uIgppbmRleFsHOxIiD2NvbnRyb2xsZXIiC3NlcnZlclsHQBMiEWFzc29jX2hhbmRsZSIke0hNQUMtU0hBMX17NTE1ODJkOTR9e2Nka28xZz09fVsHQBMiDnJldHVybl90b0APWwdAEyIKcmVhbG1ADlsHQBMiDWlkZW50aXR5IjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdDoPQGltbWVkaWF0ZUY6DkBpZGVudGl0eUAtOhJAYXNzb2NfaGFuZGxlQCY6EEBjbGFpbWVkX2lkQB06CkBtb2RlIhJjaGVja2lkX3NldHVwOhFAb3BfZW5kcG9pbnQiIWh0dHA6Ly9sb2NhbGhvc3Q6MzAwOS9zZXJ2ZXIiCmZsYXNobzolQWN0aW9uRGlzcGF0Y2g6OkZsYXNoOjpGbGFzaEhhc2gJOg1AZmxhc2hlc3sGOgtub3RpY2UiVllvdSBtdXN0IGVudGVyIGEgdXNlcm5hbWUgdG8gaW4gb3JkZXIgdG8gc2VuZCBhbiBpZGVudGlmaWVyIHRvIHRoZSBSZWx5aW5nIFBhcnR5LjoKQHVzZWRvOghTZXQGOgpAaGFzaHsAOgxAY2xvc2VkRjoJQG5vdzA=--755060a8760641df75a8c6ce57f0e8e076a90b57 hello: world last_oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.6ms) Completed 200 OK in 7ms (Views: 4.4ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 06:16:27 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"authenticity_token"=>"jgWPOedLngI1CoE4miIBy3FprrZr/xYlHnBoTWn9fOc=", "yes"=>"yes", "id_to_send"=>""} session_id: ff4ab3c2833d6324f1fcc3a4de587fe1 session_id cookie: BAh7CiIQX2NzcmZfdG9rZW4iMWpnV1BPZWRMbmdJMUNvRTRtaUlCeTNGcHJyWnIveFlsSG5Cb1RXbjlmT2M9Ig9zZXNzaW9uX2lkIiVmZjRhYjNjMjgzM2Q2MzI0ZjFmY2MzYTRkZTU4N2ZlMSIKaGVsbG8iCndvcmxkIgpmbGFzaG86JUFjdGlvbkRpc3BhdGNoOjpGbGFzaDo6Rmxhc2hIYXNoCToNQGZsYXNoZXN7BjoLbm90aWNlIlZZb3UgbXVzdCBlbnRlciBhIHVzZXJuYW1lIHRvIGluIG9yZGVyIHRvIHNlbmQgYW4gaWRlbnRpZmllciB0byB0aGUgUmVseWluZyBQYXJ0eS46CkB1c2VkbzoIU2V0BjoKQGhhc2h7ADoMQGNsb3NlZEY6CUBub3cwIhBsYXN0X29pZHJlcW86I09wZW5JRDo6U2VydmVyOjpDaGVja0lEUmVxdWVzdA46EEB0cnVzdF9yb290IiNodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXI6D0ByZXR1cm5fdG8iLGh0dHA6Ly9sb2NhbGhvc3Q6MzAxMC9jb25zdW1lci9jb21wbGV0ZToNQG1lc3NhZ2VvOhRPcGVuSUQ6Ok1lc3NhZ2UIOhBAbmFtZXNwYWNlc286GU9wZW5JRDo6TmFtZXNwYWNlTWFwCDoYQGFsaWFzX3RvX25hbWVzcGFjZXsGOhNudWxsX25hbWVzcGFjZSIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA6GUBpbXBsaWNpdF9uYW1lc3BhY2VzWwA6GEBuYW1lc3BhY2VfdG9fYWxpYXN7BiIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA7FToKQGFyZ3N7DVsHOhNiYXJlX25hbWVzcGFjZSILYWN0aW9uIgppbmRleFsHQBkiD2NsYWltZWRfaWQiN2h0dHA6Ly9zcGVjcy5vcGVuaWQubmV0L2F1dGgvMi4wL2lkZW50aWZpZXJfc2VsZWN0WwdAGSIJbW9kZSISY2hlY2tpZF9zZXR1cFsHOxkiD2NvbnRyb2xsZXIiC3NlcnZlclsHQBkiDnJldHVybl90b0AVWwdAGSIRYXNzb2NfaGFuZGxlIiR7SE1BQy1TSEExfXs1MTU4MmQ5NH17Y2RrbzFnPT19WwdAGSINaWRlbnRpdHkiN2h0dHA6Ly9zcGVjcy5vcGVuaWQubmV0L2F1dGgvMi4wL2lkZW50aWZpZXJfc2VsZWN0WwdAGSIKcmVhbG1AFDoTQG9wZW5pZF9uc191cmlAGToPQGltbWVkaWF0ZUY6DkBpZGVudGl0eUAxOhJAYXNzb2NfaGFuZGxlQC46EUBvcF9lbmRwb2ludCIhaHR0cDovL2xvY2FsaG9zdDozMDA5L3NlcnZlcjoKQG1vZGUiEmNoZWNraWRfc2V0dXA6EEBjbGFpbWVkX2lkQCM=--d18faa6ccd17ce34ee9d7d0cc67cfa3b8e5589c1 hello: world last_oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (0.6ms) Completed 200 OK in 4ms (Views: 3.1ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 06:16:32 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"authenticity_token"=>"jgWPOedLngI1CoE4miIBy3FprrZr/xYlHnBoTWn9fOc=", "yes"=>"yes", "id_to_send"=>"http://localhost:3009/marcel"} session_id: ff4ab3c2833d6324f1fcc3a4de587fe1 session_id cookie: BAh7CiIQX2NzcmZfdG9rZW4iMWpnV1BPZWRMbmdJMUNvRTRtaUlCeTNGcHJyWnIveFlsSG5Cb1RXbjlmT2M9Ig9zZXNzaW9uX2lkIiVmZjRhYjNjMjgzM2Q2MzI0ZjFmY2MzYTRkZTU4N2ZlMSIKaGVsbG8iCndvcmxkIhBsYXN0X29pZHJlcW86I09wZW5JRDo6U2VydmVyOjpDaGVja0lEUmVxdWVzdA46EEB0cnVzdF9yb290IiNodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXI6D0ByZXR1cm5fdG8iLGh0dHA6Ly9sb2NhbGhvc3Q6MzAxMC9jb25zdW1lci9jb21wbGV0ZToNQG1lc3NhZ2VvOhRPcGVuSUQ6Ok1lc3NhZ2UIOhBAbmFtZXNwYWNlc286GU9wZW5JRDo6TmFtZXNwYWNlTWFwCDoYQGFsaWFzX3RvX25hbWVzcGFjZXsGOhNudWxsX25hbWVzcGFjZSIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA6GUBpbXBsaWNpdF9uYW1lc3BhY2VzWwA6GEBuYW1lc3BhY2VfdG9fYWxpYXN7BiIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA7DToTQG9wZW5pZF9uc191cmlAEzoKQGFyZ3N7DVsHQBMiCW1vZGUiEmNoZWNraWRfc2V0dXBbB0ATIg9jbGFpbWVkX2lkIjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdFsHOhNiYXJlX25hbWVzcGFjZSILYWN0aW9uIgppbmRleFsHOxIiD2NvbnRyb2xsZXIiC3NlcnZlclsHQBMiEWFzc29jX2hhbmRsZSIke0hNQUMtU0hBMX17NTE1ODJkOTR9e2Nka28xZz09fVsHQBMiDnJldHVybl90b0APWwdAEyIKcmVhbG1ADlsHQBMiDWlkZW50aXR5IjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdDoPQGltbWVkaWF0ZUY6DkBpZGVudGl0eUAtOhJAYXNzb2NfaGFuZGxlQCY6EEBjbGFpbWVkX2lkQB06CkBtb2RlIhJjaGVja2lkX3NldHVwOhFAb3BfZW5kcG9pbnQiIWh0dHA6Ly9sb2NhbGhvc3Q6MzAwOS9zZXJ2ZXIiCmZsYXNobzolQWN0aW9uRGlzcGF0Y2g6OkZsYXNoOjpGbGFzaEhhc2gJOg1AZmxhc2hlc3sGOgtub3RpY2UiVllvdSBtdXN0IGVudGVyIGEgdXNlcm5hbWUgdG8gaW4gb3JkZXIgdG8gc2VuZCBhbiBpZGVudGlmaWVyIHRvIHRoZSBSZWx5aW5nIFBhcnR5LjoKQHVzZWRvOghTZXQGOgpAaGFzaHsAOgxAY2xvc2VkRjoJQG5vdzA=--755060a8760641df75a8c6ce57f0e8e076a90b57 hello: world last_oidreq: Redirected to http://localhost:3010/consumer/complete?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fhttp%3A%2F%2Flocalhost%3A3009%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fhttp%3A%2F%2Flocalhost%3A3009%2Fmarcel&openid.mode=id_res&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.op_endpoint=http%3A%2F%2Flocalhost%3A3009%2Fserver&openid.response_nonce=2013-03-31T13%3A16%3A32ZBnQWSS&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete&openid.sig=nk5Cd60iCeaC5tEfTFXeq8bJxkM%3D&openid.signed=assoc_handle%2Cclaimed_id%2Cidentity%2Cmode%2Cns%2Cop_endpoint%2Cresponse_nonce%2Creturn_to%2Csigned Completed 302 Found in 50ms (ActiveRecord: 0.0ms) Started GET "/consumer/complete?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fhttp%3A%2F%2Flocalhost%3A3009%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fhttp%3A%2F%2Flocalhost%3A3009%2Fmarcel&openid.mode=id_res&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.op_endpoint=http%3A%2F%2Flocalhost%3A3009%2Fserver&openid.response_nonce=2013-03-31T13%3A16%3A32ZBnQWSS&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete&openid.sig=nk5Cd60iCeaC5tEfTFXeq8bJxkM%3D&openid.signed=assoc_handle%2Cclaimed_id%2Cidentity%2Cmode%2Cns%2Cop_endpoint%2Cresponse_nonce%2Creturn_to%2Csigned" for 127.0.0.1 at Sun Mar 31 06:16:32 -0700 2013 Processing by ConsumerController#complete as HTML Parameters: {"openid.sig"=>"nk5Cd60iCeaC5tEfTFXeq8bJxkM=", "openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.op_endpoint"=>"http://localhost:3009/server", "openid.mode"=>"id_res", "openid.response_nonce"=>"2013-03-31T13:16:32ZBnQWSS", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://localhost:3009/user/http://localhost:3009/marcel", "openid.signed"=>"assoc_handle,claimed_id,identity,mode,ns,op_endpoint,response_nonce,return_to,signed", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.claimed_id"=>"http://localhost:3009/user/http://localhost:3009/marcel"} Started GET "/user/http://localhost:3009/marcel" for 127.0.0.1 at Sun Mar 31 06:16:32 -0700 2013 ActionController::RoutingError (No route matches [GET] "/user/http:/localhost:3009/marcel"): actionpack (3.2.13) lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/show_exceptions.rb:56:in `call' railties (3.2.13) lib/rails/rack/logger.rb:32:in `call_app' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' activesupport (3.2.13) lib/active_support/tagged_logging.rb:22:in `tagged' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/request_id.rb:22:in `call' rack (1.4.5) lib/rack/methodoverride.rb:21:in `call' rack (1.4.5) lib/rack/runtime.rb:17:in `call' activesupport (3.2.13) lib/active_support/cache/strategy/local_cache.rb:72:in `call' rack (1.4.5) lib/rack/lock.rb:15:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/static.rb:63:in `call' railties (3.2.13) lib/rails/engine.rb:479:in `call' railties (3.2.13) lib/rails/application.rb:223:in `call' rack (1.4.5) lib/rack/content_length.rb:14:in `call' railties (3.2.13) lib/rails/rack/log_tailer.rb:17:in `call' rack (1.4.5) lib/rack/handler/webrick.rb:59:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:104:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:65:in `run' /opt/local/lib/ruby/1.8/webrick/server.rb:173:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:95:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `each' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:23:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:82:in `start' rack (1.4.5) lib/rack/handler/webrick.rb:13:in `run' rack (1.4.5) lib/rack/server.rb:268:in `start' railties (3.2.13) lib/rails/commands/server.rb:70:in `start' railties (3.2.13) lib/rails/commands.rb:55 railties (3.2.13) lib/rails/commands.rb:50:in `tap' railties (3.2.13) lib/rails/commands.rb:50 script/rails:6:in `require' script/rails:6 Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/routing_error.erb within rescues/layout (0.6ms) Redirected to http://localhost:3010/consumer Completed 302 Found in 103ms (ActiveRecord: 0.0ms) Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 06:16:32 -0700 2013 Processing by ConsumerController#index as HTML Rendered consumer/index.html.erb within layouts/application (1.3ms) Completed 200 OK in 229ms (Views: 219.6ms | ActiveRecord: 0.0ms) Started GET "/assets/application.css?body=1" for 127.0.0.1 at Sun Mar 31 06:16:32 -0700 2013 Served asset /application.css - 304 Not Modified (0ms) Started GET "/assets/jquery.js?body=1" for 127.0.0.1 at Sun Mar 31 06:16:32 -0700 2013 Served asset /jquery.js - 304 Not Modified (0ms) Started GET "/assets/application.js?body=1" for 127.0.0.1 at Sun Mar 31 06:16:32 -0700 2013 Served asset /application.js - 304 Not Modified (0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 06:16:53 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"authenticity_token"=>"jgWPOedLngI1CoE4miIBy3FprrZr/xYlHnBoTWn9fOc=", "yes"=>"yes", "id_to_send"=>"marcel"} session_id: ff4ab3c2833d6324f1fcc3a4de587fe1 session_id cookie: BAh7CyIQX2NzcmZfdG9rZW4iMWpnV1BPZWRMbmdJMUNvRTRtaUlCeTNGcHJyWnIveFlsSG5Cb1RXbjlmT2M9Ig9zZXNzaW9uX2lkIiVmZjRhYjNjMjgzM2Q2MzI0ZjFmY2MzYTRkZTU4N2ZlMSINdXNlcm5hbWUiIWh0dHA6Ly9sb2NhbGhvc3Q6MzAwOS9tYXJjZWwiCmhlbGxvIgp3b3JsZCIKZmxhc2hvOiVBY3Rpb25EaXNwYXRjaDo6Rmxhc2g6OkZsYXNoSGFzaAk6DUBmbGFzaGVzewY6CmVycm9yIgGaVmVyaWZpY2F0aW9uIGZhaWxlZDogSFRUUCBSZXNwb25zZSBzdGF0dXMgZnJvbSBpZGVudGl0eSBVUkwgaG9zdCBpcyBub3QgIjIwMCIuR290IHN0YXR1cyAiNDA0IiBmb3IgaHR0cDovL2xvY2FsaG9zdDozMDA5L3VzZXIvaHR0cDovL2xvY2FsaG9zdDozMDA5L21hcmNlbDoKQHVzZWRvOghTZXQGOgpAaGFzaHsGOwdUOgxAY2xvc2VkRjoJQG5vdzAiDmFwcHJvdmFsc1sGIiNodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXI=--419dee51ac0f7222ab6c721397583a987665e92b hello: world last_oidreq: Rendered text template (0.0ms) Completed 200 OK in 1ms (Views: 0.5ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 06:16:57 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"authenticity_token"=>"jgWPOedLngI1CoE4miIBy3FprrZr/xYlHnBoTWn9fOc=", "yes"=>"yes", "id_to_send"=>""} session_id: ff4ab3c2833d6324f1fcc3a4de587fe1 session_id cookie: BAh7CiIQX2NzcmZfdG9rZW4iMWpnV1BPZWRMbmdJMUNvRTRtaUlCeTNGcHJyWnIveFlsSG5Cb1RXbjlmT2M9Ig11c2VybmFtZSIhaHR0cDovL2xvY2FsaG9zdDozMDA5L21hcmNlbCIPc2Vzc2lvbl9pZCIlZmY0YWIzYzI4MzNkNjMyNGYxZmNjM2E0ZGU1ODdmZTEiCmhlbGxvIgp3b3JsZCIOYXBwcm92YWxzWwYiI2h0dHA6Ly9sb2NhbGhvc3Q6MzAxMC9jb25zdW1lcg==--793b2103b83a8f1f36926f105f4f81683d9f5a7f hello: world last_oidreq: Rendered text template (0.0ms) Completed 200 OK in 1ms (Views: 0.6ms | ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 06:17:08 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} Redirected to http://localhost:3010/consumer/complete?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fhttp%3A%2F%2Flocalhost%3A3009%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fhttp%3A%2F%2Flocalhost%3A3009%2Fmarcel&openid.mode=id_res&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.op_endpoint=http%3A%2F%2Flocalhost%3A3009%2Fserver&openid.response_nonce=2013-03-31T13%3A17%3A08ZUxQiz5&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete&openid.sig=4HAQxaR%2B5Mujm5aHJjPjV8E6kPo%3D&openid.signed=assoc_handle%2Cclaimed_id%2Cidentity%2Cmode%2Cns%2Cop_endpoint%2Cresponse_nonce%2Creturn_to%2Csigned Completed 302 Found in 196ms (ActiveRecord: 0.0ms) Started GET "/consumer/complete?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fhttp%3A%2F%2Flocalhost%3A3009%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fhttp%3A%2F%2Flocalhost%3A3009%2Fmarcel&openid.mode=id_res&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.op_endpoint=http%3A%2F%2Flocalhost%3A3009%2Fserver&openid.response_nonce=2013-03-31T13%3A17%3A08ZUxQiz5&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete&openid.sig=4HAQxaR%2B5Mujm5aHJjPjV8E6kPo%3D&openid.signed=assoc_handle%2Cclaimed_id%2Cidentity%2Cmode%2Cns%2Cop_endpoint%2Cresponse_nonce%2Creturn_to%2Csigned" for 127.0.0.1 at Sun Mar 31 06:17:09 -0700 2013 Processing by ConsumerController#complete as HTML Parameters: {"openid.sig"=>"4HAQxaR+5Mujm5aHJjPjV8E6kPo=", "openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.op_endpoint"=>"http://localhost:3009/server", "openid.mode"=>"id_res", "openid.response_nonce"=>"2013-03-31T13:17:08ZUxQiz5", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://localhost:3009/user/http://localhost:3009/marcel", "openid.signed"=>"assoc_handle,claimed_id,identity,mode,ns,op_endpoint,response_nonce,return_to,signed", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.claimed_id"=>"http://localhost:3009/user/http://localhost:3009/marcel"} Started GET "/user/http://localhost:3009/marcel" for 127.0.0.1 at Sun Mar 31 06:17:09 -0700 2013 ActionController::RoutingError (No route matches [GET] "/user/http:/localhost:3009/marcel"): actionpack (3.2.13) lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/show_exceptions.rb:56:in `call' railties (3.2.13) lib/rails/rack/logger.rb:32:in `call_app' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' activesupport (3.2.13) lib/active_support/tagged_logging.rb:22:in `tagged' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/request_id.rb:22:in `call' rack (1.4.5) lib/rack/methodoverride.rb:21:in `call' rack (1.4.5) lib/rack/runtime.rb:17:in `call' activesupport (3.2.13) lib/active_support/cache/strategy/local_cache.rb:72:in `call' rack (1.4.5) lib/rack/lock.rb:15:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/static.rb:63:in `call' railties (3.2.13) lib/rails/engine.rb:479:in `call' railties (3.2.13) lib/rails/application.rb:223:in `call' rack (1.4.5) lib/rack/content_length.rb:14:in `call' railties (3.2.13) lib/rails/rack/log_tailer.rb:17:in `call' rack (1.4.5) lib/rack/handler/webrick.rb:59:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:104:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:65:in `run' /opt/local/lib/ruby/1.8/webrick/server.rb:173:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:95:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `each' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:23:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:82:in `start' rack (1.4.5) lib/rack/handler/webrick.rb:13:in `run' rack (1.4.5) lib/rack/server.rb:268:in `start' railties (3.2.13) lib/rails/commands/server.rb:70:in `start' railties (3.2.13) lib/rails/commands.rb:55 railties (3.2.13) lib/rails/commands.rb:50:in `tap' railties (3.2.13) lib/rails/commands.rb:50 script/rails:6:in `require' script/rails:6 Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/routing_error.erb within rescues/layout (3.2ms) Redirected to http://localhost:3010/consumer Completed 302 Found in 70ms (ActiveRecord: 0.0ms) Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 06:17:09 -0700 2013 Processing by ConsumerController#index as HTML Rendered consumer/index.html.erb within layouts/application (1.1ms) Completed 200 OK in 21ms (Views: 17.4ms | ActiveRecord: 0.0ms) Started GET "/assets/application.css?body=1" for 127.0.0.1 at Sun Mar 31 06:17:09 -0700 2013 Served asset /application.css - 304 Not Modified (0ms) Started GET "/assets/application.js?body=1" for 127.0.0.1 at Sun Mar 31 06:17:09 -0700 2013 Served asset /application.js - 304 Not Modified (0ms) Started GET "/assets/jquery.js?body=1" for 127.0.0.1 at Sun Mar 31 06:17:09 -0700 2013 Served asset /jquery.js - 304 Not Modified (0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 06:17:16 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} Redirected to http://localhost:3010/consumer/complete?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fhttp%3A%2F%2Flocalhost%3A3009%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fhttp%3A%2F%2Flocalhost%3A3009%2Fmarcel&openid.mode=id_res&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.op_endpoint=http%3A%2F%2Flocalhost%3A3009%2Fserver&openid.response_nonce=2013-03-31T13%3A17%3A16ZE1EQft&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete&openid.sig=EBYQ%2BmvGOdl6C1fW2uvPjRS3XMk%3D&openid.signed=assoc_handle%2Cclaimed_id%2Cidentity%2Cmode%2Cns%2Cop_endpoint%2Cresponse_nonce%2Creturn_to%2Csigned Completed 302 Found in 25ms (ActiveRecord: 0.0ms) Started GET "/consumer/complete?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fhttp%3A%2F%2Flocalhost%3A3009%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fhttp%3A%2F%2Flocalhost%3A3009%2Fmarcel&openid.mode=id_res&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.op_endpoint=http%3A%2F%2Flocalhost%3A3009%2Fserver&openid.response_nonce=2013-03-31T13%3A17%3A16ZE1EQft&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete&openid.sig=EBYQ%2BmvGOdl6C1fW2uvPjRS3XMk%3D&openid.signed=assoc_handle%2Cclaimed_id%2Cidentity%2Cmode%2Cns%2Cop_endpoint%2Cresponse_nonce%2Creturn_to%2Csigned" for 127.0.0.1 at Sun Mar 31 06:17:16 -0700 2013 Processing by ConsumerController#complete as HTML Parameters: {"openid.sig"=>"EBYQ+mvGOdl6C1fW2uvPjRS3XMk=", "openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.op_endpoint"=>"http://localhost:3009/server", "openid.mode"=>"id_res", "openid.response_nonce"=>"2013-03-31T13:17:16ZE1EQft", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://localhost:3009/user/http://localhost:3009/marcel", "openid.signed"=>"assoc_handle,claimed_id,identity,mode,ns,op_endpoint,response_nonce,return_to,signed", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.claimed_id"=>"http://localhost:3009/user/http://localhost:3009/marcel"} Started GET "/user/http://localhost:3009/marcel" for 127.0.0.1 at Sun Mar 31 06:17:16 -0700 2013 ActionController::RoutingError (No route matches [GET] "/user/http:/localhost:3009/marcel"): actionpack (3.2.13) lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/show_exceptions.rb:56:in `call' railties (3.2.13) lib/rails/rack/logger.rb:32:in `call_app' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' activesupport (3.2.13) lib/active_support/tagged_logging.rb:22:in `tagged' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/request_id.rb:22:in `call' rack (1.4.5) lib/rack/methodoverride.rb:21:in `call' rack (1.4.5) lib/rack/runtime.rb:17:in `call' activesupport (3.2.13) lib/active_support/cache/strategy/local_cache.rb:72:in `call' rack (1.4.5) lib/rack/lock.rb:15:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/static.rb:63:in `call' railties (3.2.13) lib/rails/engine.rb:479:in `call' railties (3.2.13) lib/rails/application.rb:223:in `call' rack (1.4.5) lib/rack/content_length.rb:14:in `call' railties (3.2.13) lib/rails/rack/log_tailer.rb:17:in `call' rack (1.4.5) lib/rack/handler/webrick.rb:59:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:104:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:65:in `run' /opt/local/lib/ruby/1.8/webrick/server.rb:173:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:95:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `each' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:23:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:82:in `start' rack (1.4.5) lib/rack/handler/webrick.rb:13:in `run' rack (1.4.5) lib/rack/server.rb:268:in `start' railties (3.2.13) lib/rails/commands/server.rb:70:in `start' railties (3.2.13) lib/rails/commands.rb:55 railties (3.2.13) lib/rails/commands.rb:50:in `tap' railties (3.2.13) lib/rails/commands.rb:50 script/rails:6:in `require' script/rails:6 Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/routing_error.erb within rescues/layout (0.7ms) Redirected to http://localhost:3010/consumer Completed 302 Found in 62ms (ActiveRecord: 0.0ms) Started GET "/assets/application.css?body=1" for 127.0.0.1 at Sun Mar 31 06:17:16 -0700 2013 Served asset /application.css - 304 Not Modified (0ms) Started GET "/assets/jquery.js?body=1" for 127.0.0.1 at Sun Mar 31 06:17:16 -0700 2013 Served asset /jquery.js - 304 Not Modified (0ms) Started GET "/assets/application.js?body=1" for 127.0.0.1 at Sun Mar 31 06:17:16 -0700 2013 Served asset /application.js - 304 Not Modified (0ms) Started GET "/consumer/start?openid_identifier=http%3A%2F%2Flocalhost%3A3009%2Fserver%2Fidp_xrds" for 127.0.0.1 at Sun Mar 31 06:17:26 -0700 2013 Processing by ConsumerController#start as HTML Parameters: {"openid_identifier"=>"http://localhost:3009/server/idp_xrds"} Started GET "/server/idp_xrds" for 127.0.0.1 at Sun Mar 31 06:17:26 -0700 2013 Processing by ServerController#idp_xrds as application/xrds+xml Rendered text template (0.0ms) Completed 200 OK in 2ms (Views: 0.6ms | ActiveRecord: 0.0ms) Redirected to http://localhost:3009/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete Completed 302 Found in 60ms (ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 06:17:26 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} Redirected to http://localhost:3010/consumer/complete?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fhttp%3A%2F%2Flocalhost%3A3009%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fhttp%3A%2F%2Flocalhost%3A3009%2Fmarcel&openid.mode=id_res&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.op_endpoint=http%3A%2F%2Flocalhost%3A3009%2Fserver&openid.response_nonce=2013-03-31T13%3A17%3A26Z1eD29V&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete&openid.sig=MXD7sDIZw8q8tsYYlj%2FAsSmIHTg%3D&openid.signed=assoc_handle%2Cclaimed_id%2Cidentity%2Cmode%2Cns%2Cop_endpoint%2Cresponse_nonce%2Creturn_to%2Csigned Completed 302 Found in 27ms (ActiveRecord: 0.0ms) Started GET "/consumer/complete?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fhttp%3A%2F%2Flocalhost%3A3009%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fhttp%3A%2F%2Flocalhost%3A3009%2Fmarcel&openid.mode=id_res&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.op_endpoint=http%3A%2F%2Flocalhost%3A3009%2Fserver&openid.response_nonce=2013-03-31T13%3A17%3A26Z1eD29V&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete&openid.sig=MXD7sDIZw8q8tsYYlj%2FAsSmIHTg%3D&openid.signed=assoc_handle%2Cclaimed_id%2Cidentity%2Cmode%2Cns%2Cop_endpoint%2Cresponse_nonce%2Creturn_to%2Csigned" for 127.0.0.1 at Sun Mar 31 06:17:26 -0700 2013 Processing by ConsumerController#complete as HTML Parameters: {"openid.sig"=>"MXD7sDIZw8q8tsYYlj/AsSmIHTg=", "openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.op_endpoint"=>"http://localhost:3009/server", "openid.mode"=>"id_res", "openid.response_nonce"=>"2013-03-31T13:17:26Z1eD29V", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://localhost:3009/user/http://localhost:3009/marcel", "openid.signed"=>"assoc_handle,claimed_id,identity,mode,ns,op_endpoint,response_nonce,return_to,signed", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.claimed_id"=>"http://localhost:3009/user/http://localhost:3009/marcel"} Started GET "/user/http://localhost:3009/marcel" for 127.0.0.1 at Sun Mar 31 06:17:26 -0700 2013 ActionController::RoutingError (No route matches [GET] "/user/http:/localhost:3009/marcel"): actionpack (3.2.13) lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/show_exceptions.rb:56:in `call' railties (3.2.13) lib/rails/rack/logger.rb:32:in `call_app' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' activesupport (3.2.13) lib/active_support/tagged_logging.rb:22:in `tagged' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/request_id.rb:22:in `call' rack (1.4.5) lib/rack/methodoverride.rb:21:in `call' rack (1.4.5) lib/rack/runtime.rb:17:in `call' activesupport (3.2.13) lib/active_support/cache/strategy/local_cache.rb:72:in `call' rack (1.4.5) lib/rack/lock.rb:15:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/static.rb:63:in `call' railties (3.2.13) lib/rails/engine.rb:479:in `call' railties (3.2.13) lib/rails/application.rb:223:in `call' rack (1.4.5) lib/rack/content_length.rb:14:in `call' railties (3.2.13) lib/rails/rack/log_tailer.rb:17:in `call' rack (1.4.5) lib/rack/handler/webrick.rb:59:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:104:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:65:in `run' /opt/local/lib/ruby/1.8/webrick/server.rb:173:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:95:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `each' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:23:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:82:in `start' rack (1.4.5) lib/rack/handler/webrick.rb:13:in `run' rack (1.4.5) lib/rack/server.rb:268:in `start' railties (3.2.13) lib/rails/commands/server.rb:70:in `start' railties (3.2.13) lib/rails/commands.rb:55 railties (3.2.13) lib/rails/commands.rb:50:in `tap' railties (3.2.13) lib/rails/commands.rb:50 script/rails:6:in `require' script/rails:6 Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/routing_error.erb within rescues/layout (0.6ms) Redirected to http://localhost:3010/consumer Completed 302 Found in 61ms (ActiveRecord: 0.0ms) Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 06:17:26 -0700 2013 Processing by ConsumerController#index as HTML Rendered consumer/index.html.erb within layouts/application (0.8ms) Completed 200 OK in 11ms (Views: 10.5ms | ActiveRecord: 0.0ms) Started GET "/assets/application.js?body=1" for 127.0.0.1 at Sun Mar 31 06:17:26 -0700 2013 Served asset /application.js - 304 Not Modified (0ms) Started GET "/assets/jquery.js?body=1" for 127.0.0.1 at Sun Mar 31 06:17:26 -0700 2013 Served asset /jquery.js - 304 Not Modified (0ms) Started GET "/assets/application.css?body=1" for 127.0.0.1 at Sun Mar 31 06:17:26 -0700 2013 Served asset /application.css - 304 Not Modified (0ms) Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 06:17:59 -0700 2013 Processing by ConsumerController#index as HTML Rendered consumer/index.html.erb within layouts/application (0.7ms) Completed 200 OK in 10ms (Views: 9.6ms | ActiveRecord: 0.0ms) Started GET "/assets/application.css?body=1" for 127.0.0.1 at Sun Mar 31 06:17:59 -0700 2013 Served asset /application.css - 304 Not Modified (0ms) Started GET "/assets/jquery.js?body=1" for 127.0.0.1 at Sun Mar 31 06:17:59 -0700 2013 Served asset /jquery.js - 304 Not Modified (0ms) Started GET "/assets/application.js?body=1" for 127.0.0.1 at Sun Mar 31 06:17:59 -0700 2013 Served asset /application.js - 304 Not Modified (0ms) Started GET "/consumer/start?openid_identifier=http%3A%2F%2Flocalhost%3A3009%2Fserver%2Fidp_xrds" for 127.0.0.1 at Sun Mar 31 06:18:07 -0700 2013 Processing by ConsumerController#start as HTML Parameters: {"openid_identifier"=>"http://localhost:3009/server/idp_xrds"} Started GET "/server/idp_xrds" for 127.0.0.1 at Sun Mar 31 06:18:07 -0700 2013 Processing by ServerController#idp_xrds as application/xrds+xml Rendered text template (0.0ms) Completed 200 OK in 2ms (Views: 0.8ms | ActiveRecord: 0.0ms) Redirected to http://localhost:3009/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete Completed 302 Found in 26ms (ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 06:18:07 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://specs.openid.net/auth/2.0/identifier_select", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://specs.openid.net/auth/2.0/identifier_select"} The user hasn't logged in oidreq: Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (6.2ms) session last_oidreq: session last_oidreq size: 804 session_id: d6218bef503e314e9d7332aad45fbbc9 session_id cookie: BAh7CSIQX2NzcmZfdG9rZW4iMXlHVTJMb2V0MUZ0ZEZRUVcyZityYkJtTFVBZWkxT0lJczNpRUE5cmpUQms9Ii5PcGVuSUQ6OkNvbnN1bWVyOjpsYXN0X3JlcXVlc3RlZF9lbmRwb2ludG86Ik9wZW5JRDo6T3BlbklEU2VydmljZUVuZHBvaW50DDoSQGNhbm9uaWNhbF9pZDA6EEBjbGFpbWVkX2lkMDoOQGxvY2FsX2lkMDoYQGRpc3BsYXlfaWRlbnRpZmllcjA6D0B0eXBlX3VyaXNbBiIsaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjAvc2VydmVyOhBAdXNlZF95YWRpc1Q6EEBzZXJ2ZXJfdXJsIiFodHRwOi8vbG9jYWxob3N0OjMwMDkvc2VydmVyIg9zZXNzaW9uX2lkIiVkNjIxOGJlZjUwM2UzMTRlOWQ3MzMyYWFkNDVmYmJjOSI9T3BlbklEOjpDb25zdW1lcjo6RGlzY292ZXJlZFNlcnZpY2VzOjpPcGVuSUQ6OkNvbnN1bWVyOjpvOilPcGVuSUQ6OkNvbnN1bWVyOjpEaXNjb3ZlcmVkU2VydmljZXMJOhJAc3RhcnRpbmdfdXJsIipodHRwOi8vbG9jYWxob3N0OjMwMDkvc2VydmVyL2lkcF94cmRzOg9AeWFkaXNfdXJsIipodHRwOi8vbG9jYWxob3N0OjMwMDkvc2VydmVyL2lkcF94cmRzOg1AY3VycmVudEAJOg5Ac2VydmljZXNbAA==--41e24383267c05452a1bcd365b2ce4c9c5156926 Completed 200 OK in 24ms (Views: 16.2ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 06:18:11 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"authenticity_token"=>"yGU2Loet1FtdFQQW2f+rbBmLUAei1OIIs3iEA9rjTBk=", "yes"=>"yes", "id_to_send"=>"marcel"} session_id: d6218bef503e314e9d7332aad45fbbc9 session_id cookie: BAh7DCIuT3BlbklEOjpDb25zdW1lcjo6bGFzdF9yZXF1ZXN0ZWRfZW5kcG9pbnRvOiJPcGVuSUQ6Ok9wZW5JRFNlcnZpY2VFbmRwb2ludAw6DkBsb2NhbF9pZDA6GEBkaXNwbGF5X2lkZW50aWZpZXIwOg9AdHlwZV91cmlzWwYiLGh0dHA6Ly9zcGVjcy5vcGVuaWQubmV0L2F1dGgvMi4wL3NlcnZlcjoQQHVzZWRfeWFkaXNUOhBAc2VydmVyX3VybCIhaHR0cDovL2xvY2FsaG9zdDozMDA5L3NlcnZlcjoSQGNhbm9uaWNhbF9pZDA6EEBjbGFpbWVkX2lkMCIQX2NzcmZfdG9rZW4iMXlHVTJMb2V0MUZ0ZEZRUVcyZityYkJtTFVBZWkxT0lJczNpRUE5cmpUQms9Ig9zZXNzaW9uX2lkIiVkNjIxOGJlZjUwM2UzMTRlOWQ3MzMyYWFkNDVmYmJjOSIKaGVsbG8iCndvcmxkIj1PcGVuSUQ6OkNvbnN1bWVyOjpEaXNjb3ZlcmVkU2VydmljZXM6Ok9wZW5JRDo6Q29uc3VtZXI6Om86KU9wZW5JRDo6Q29uc3VtZXI6OkRpc2NvdmVyZWRTZXJ2aWNlcwk6D0B5YWRpc191cmwiKmh0dHA6Ly9sb2NhbGhvc3Q6MzAwOS9zZXJ2ZXIvaWRwX3hyZHM6DkBzZXJ2aWNlc1sAOhJAc3RhcnRpbmdfdXJsIipodHRwOi8vbG9jYWxob3N0OjMwMDkvc2VydmVyL2lkcF94cmRzOg1AY3VycmVudEAHIhBsYXN0X29pZHJlcW86I09wZW5JRDo6U2VydmVyOjpDaGVja0lEUmVxdWVzdA46EEB0cnVzdF9yb290IiNodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXI6D0ByZXR1cm5fdG8iLGh0dHA6Ly9sb2NhbGhvc3Q6MzAxMC9jb25zdW1lci9jb21wbGV0ZToNQG1lc3NhZ2VvOhRPcGVuSUQ6Ok1lc3NhZ2UIOhBAbmFtZXNwYWNlc286GU9wZW5JRDo6TmFtZXNwYWNlTWFwCDoYQGFsaWFzX3RvX25hbWVzcGFjZXsGOhNudWxsX25hbWVzcGFjZSIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA6GUBpbXBsaWNpdF9uYW1lc3BhY2VzWwA6GEBuYW1lc3BhY2VfdG9fYWxpYXN7BiIlaHR0cDovL3NwZWNzLm9wZW5pZC5uZXQvYXV0aC8yLjA7GjoTQG9wZW5pZF9uc191cmlAHToKQGFyZ3N7DVsHQB0iCW1vZGUiEmNoZWNraWRfc2V0dXBbB0AdIg9jbGFpbWVkX2lkIjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdFsHOhNiYXJlX25hbWVzcGFjZSILYWN0aW9uIgppbmRleFsHOx8iD2NvbnRyb2xsZXIiC3NlcnZlclsHQB0iEWFzc29jX2hhbmRsZSIke0hNQUMtU0hBMX17NTE1ODJkOTR9e2Nka28xZz09fVsHQB0iDnJldHVybl90b0AZWwdAHSIKcmVhbG1AGFsHQB0iDWlkZW50aXR5IjdodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMC9pZGVudGlmaWVyX3NlbGVjdDoPQGltbWVkaWF0ZUY6DkBpZGVudGl0eUA3OhJAYXNzb2NfaGFuZGxlQDA7DEAnOgpAbW9kZSISY2hlY2tpZF9zZXR1cDoRQG9wX2VuZHBvaW50IiFodHRwOi8vbG9jYWxob3N0OjMwMDkvc2VydmVyIgpmbGFzaG86JUFjdGlvbkRpc3BhdGNoOjpGbGFzaDo6Rmxhc2hIYXNoCToNQGZsYXNoZXN7BjoLbm90aWNlIi9EbyB5b3UgdHJ1c3QgdGhpcyBzaXRlIHdpdGggeW91ciBpZGVudGl0eT86CkB1c2VkbzoIU2V0BjoKQGhhc2h7ADoMQGNsb3NlZEY6CUBub3cw--279369ace44ed4ba1137444c001224c933b254aa hello: world last_oidreq: Redirected to http://localhost:3010/consumer/complete?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fmarcel&openid.mode=id_res&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.op_endpoint=http%3A%2F%2Flocalhost%3A3009%2Fserver&openid.response_nonce=2013-03-31T13%3A18%3A11ZrhmBhZ&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete&openid.sig=VeJwgcmZ8yfGmhLFDsQnLFt4E%2FA%3D&openid.signed=assoc_handle%2Cclaimed_id%2Cidentity%2Cmode%2Cns%2Cop_endpoint%2Cresponse_nonce%2Creturn_to%2Csigned Completed 302 Found in 14ms (ActiveRecord: 0.0ms) Started GET "/consumer/complete?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fmarcel&openid.mode=id_res&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.op_endpoint=http%3A%2F%2Flocalhost%3A3009%2Fserver&openid.response_nonce=2013-03-31T13%3A18%3A11ZrhmBhZ&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete&openid.sig=VeJwgcmZ8yfGmhLFDsQnLFt4E%2FA%3D&openid.signed=assoc_handle%2Cclaimed_id%2Cidentity%2Cmode%2Cns%2Cop_endpoint%2Cresponse_nonce%2Creturn_to%2Csigned" for 127.0.0.1 at Sun Mar 31 06:18:11 -0700 2013 Processing by ConsumerController#complete as HTML Parameters: {"openid.sig"=>"VeJwgcmZ8yfGmhLFDsQnLFt4E/A=", "openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.op_endpoint"=>"http://localhost:3009/server", "openid.mode"=>"id_res", "openid.response_nonce"=>"2013-03-31T13:18:11ZrhmBhZ", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://localhost:3009/user/marcel", "openid.signed"=>"assoc_handle,claimed_id,identity,mode,ns,op_endpoint,response_nonce,return_to,signed", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.claimed_id"=>"http://localhost:3009/user/marcel"} Started GET "/user/marcel" for 127.0.0.1 at Sun Mar 31 06:18:11 -0700 2013 ActionController::RoutingError (No route matches [GET] "/user/marcel"): actionpack (3.2.13) lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/show_exceptions.rb:56:in `call' railties (3.2.13) lib/rails/rack/logger.rb:32:in `call_app' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' activesupport (3.2.13) lib/active_support/tagged_logging.rb:22:in `tagged' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/request_id.rb:22:in `call' rack (1.4.5) lib/rack/methodoverride.rb:21:in `call' rack (1.4.5) lib/rack/runtime.rb:17:in `call' activesupport (3.2.13) lib/active_support/cache/strategy/local_cache.rb:72:in `call' rack (1.4.5) lib/rack/lock.rb:15:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/static.rb:63:in `call' railties (3.2.13) lib/rails/engine.rb:479:in `call' railties (3.2.13) lib/rails/application.rb:223:in `call' rack (1.4.5) lib/rack/content_length.rb:14:in `call' railties (3.2.13) lib/rails/rack/log_tailer.rb:17:in `call' rack (1.4.5) lib/rack/handler/webrick.rb:59:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:104:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:65:in `run' /opt/local/lib/ruby/1.8/webrick/server.rb:173:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:95:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `each' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:23:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:82:in `start' rack (1.4.5) lib/rack/handler/webrick.rb:13:in `run' rack (1.4.5) lib/rack/server.rb:268:in `start' railties (3.2.13) lib/rails/commands/server.rb:70:in `start' railties (3.2.13) lib/rails/commands.rb:55 railties (3.2.13) lib/rails/commands.rb:50:in `tap' railties (3.2.13) lib/rails/commands.rb:50 script/rails:6:in `require' script/rails:6 Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/routing_error.erb within rescues/layout (0.7ms) Redirected to http://localhost:3010/consumer Completed 302 Found in 42ms (ActiveRecord: 0.0ms) Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 06:18:11 -0700 2013 Processing by ConsumerController#index as HTML Rendered consumer/index.html.erb within layouts/application (0.8ms) Completed 200 OK in 7ms (Views: 6.8ms | ActiveRecord: 0.0ms) Started GET "/assets/application.css?body=1" for 127.0.0.1 at Sun Mar 31 06:18:11 -0700 2013 Served asset /application.css - 304 Not Modified (0ms) Started GET "/assets/jquery.js?body=1" for 127.0.0.1 at Sun Mar 31 06:18:11 -0700 2013 Served asset /jquery.js - 304 Not Modified (0ms) Started GET "/assets/application.js?body=1" for 127.0.0.1 at Sun Mar 31 06:18:11 -0700 2013 Served asset /application.js - 304 Not Modified (0ms) Started GET "/assets/rails.png" for 127.0.0.1 at Sun Mar 31 06:24:32 -0700 2013 NameError (undefined local variable or method `map' for #): config/routes.rb:2 config/routes.rb:1 Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.7ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (1.1ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (18.2ms) Started GET "/" for 127.0.0.1 at Sun Mar 31 06:24:41 -0700 2013 ActionController::RoutingError (No route matches [GET] "/"): actionpack (3.2.13) lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/show_exceptions.rb:56:in `call' railties (3.2.13) lib/rails/rack/logger.rb:32:in `call_app' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' activesupport (3.2.13) lib/active_support/tagged_logging.rb:22:in `tagged' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/request_id.rb:22:in `call' rack (1.4.5) lib/rack/methodoverride.rb:21:in `call' rack (1.4.5) lib/rack/runtime.rb:17:in `call' activesupport (3.2.13) lib/active_support/cache/strategy/local_cache.rb:72:in `call' rack (1.4.5) lib/rack/lock.rb:15:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/static.rb:63:in `call' railties (3.2.13) lib/rails/engine.rb:479:in `call' railties (3.2.13) lib/rails/application.rb:223:in `call' rack (1.4.5) lib/rack/content_length.rb:14:in `call' railties (3.2.13) lib/rails/rack/log_tailer.rb:17:in `call' rack (1.4.5) lib/rack/handler/webrick.rb:59:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:104:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:65:in `run' /opt/local/lib/ruby/1.8/webrick/server.rb:173:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:95:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `each' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:23:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:82:in `start' rack (1.4.5) lib/rack/handler/webrick.rb:13:in `run' rack (1.4.5) lib/rack/server.rb:268:in `start' railties (3.2.13) lib/rails/commands/server.rb:70:in `start' railties (3.2.13) lib/rails/commands.rb:55 railties (3.2.13) lib/rails/commands.rb:50:in `tap' railties (3.2.13) lib/rails/commands.rb:50 script/rails:6:in `require' script/rails:6 Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/routing_error.erb within rescues/layout (0.6ms) Connecting to database specified by database.yml Connecting to database specified by database.yml Connecting to database specified by database.yml Connecting to database specified by database.yml Started GET "/" for 127.0.0.1 at Sun Mar 31 06:28:03 -0700 2013 ActionDispatch::Session::SessionRestoreError (Session contains objects whose class definition isn't available. Remember to require the classes for all objects kept in the session. (Original exception: uninitialized constant OpenID [NameError]) ): actionpack (3.2.13) lib/action_dispatch/middleware/session/abstract_store.rb:64:in `stale_session_check!' actionpack (3.2.13) lib/action_dispatch/middleware/session/cookie_store.rb:48:in `unpacked_cookie_data' rack (1.4.5) lib/rack/session/cookie.rb:107:in `extract_session_id' actionpack (3.2.13) lib/action_dispatch/middleware/session/abstract_store.rb:53:in `extract_session_id' actionpack (3.2.13) lib/action_dispatch/middleware/session/abstract_store.rb:57:in `stale_session_check!' actionpack (3.2.13) lib/action_dispatch/middleware/session/abstract_store.rb:53:in `extract_session_id' rack (1.4.5) lib/rack/session/abstract/id.rb:43:in `send' rack (1.4.5) lib/rack/session/abstract/id.rb:43:in `load_session_id!' rack (1.4.5) lib/rack/session/abstract/id.rb:32:in `[]' rack (1.4.5) lib/rack/session/abstract/id.rb:267:in `current_session_id' rack (1.4.5) lib/rack/session/abstract/id.rb:273:in `session_exists?' rack (1.4.5) lib/rack/session/abstract/id.rb:107:in `send' rack (1.4.5) lib/rack/session/abstract/id.rb:107:in `exists?' rack (1.4.5) lib/rack/session/abstract/id.rb:127:in `load_for_read!' rack (1.4.5) lib/rack/session/abstract/id.rb:64:in `key?' actionpack (3.2.13) lib/action_dispatch/middleware/flash.rb:258:in `call' rack (1.4.5) lib/rack/session/abstract/id.rb:210:in `context' rack (1.4.5) lib/rack/session/abstract/id.rb:205:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/cookies.rb:341:in `call' activerecord (3.2.13) lib/active_record/query_cache.rb:64:in `call' activerecord (3.2.13) lib/active_record/connection_adapters/abstract/connection_pool.rb:479:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/callbacks.rb:28:in `call' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `_run__397314981__call__4__callbacks' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `send' activesupport (3.2.13) lib/active_support/callbacks.rb:405:in `__run_callback' activesupport (3.2.13) lib/active_support/callbacks.rb:385:in `_run_call_callbacks' activesupport (3.2.13) lib/active_support/callbacks.rb:81:in `send' activesupport (3.2.13) lib/active_support/callbacks.rb:81:in `run_callbacks' actionpack (3.2.13) lib/action_dispatch/middleware/callbacks.rb:27:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/reloader.rb:65:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/remote_ip.rb:31:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/debug_exceptions.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/show_exceptions.rb:56:in `call' railties (3.2.13) lib/rails/rack/logger.rb:32:in `call_app' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' activesupport (3.2.13) lib/active_support/tagged_logging.rb:22:in `tagged' railties (3.2.13) lib/rails/rack/logger.rb:16:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/request_id.rb:22:in `call' rack (1.4.5) lib/rack/methodoverride.rb:21:in `call' rack (1.4.5) lib/rack/runtime.rb:17:in `call' activesupport (3.2.13) lib/active_support/cache/strategy/local_cache.rb:72:in `call' rack (1.4.5) lib/rack/lock.rb:15:in `call' actionpack (3.2.13) lib/action_dispatch/middleware/static.rb:63:in `call' railties (3.2.13) lib/rails/engine.rb:479:in `call' railties (3.2.13) lib/rails/application.rb:223:in `call' rack (1.4.5) lib/rack/content_length.rb:14:in `call' railties (3.2.13) lib/rails/rack/log_tailer.rb:17:in `call' rack (1.4.5) lib/rack/handler/webrick.rb:59:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:104:in `service' /opt/local/lib/ruby/1.8/webrick/httpserver.rb:65:in `run' /opt/local/lib/ruby/1.8/webrick/server.rb:173:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start_thread' /opt/local/lib/ruby/1.8/webrick/server.rb:95:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `each' /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:23:in `start' /opt/local/lib/ruby/1.8/webrick/server.rb:82:in `start' rack (1.4.5) lib/rack/handler/webrick.rb:13:in `run' rack (1.4.5) lib/rack/server.rb:268:in `start' railties (3.2.13) lib/rails/commands/server.rb:70:in `start' railties (3.2.13) lib/rails/commands.rb:55 railties (3.2.13) lib/rails/commands.rb:50:in `tap' railties (3.2.13) lib/rails/commands.rb:50 script/rails:6:in `require' script/rails:6 Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.6ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (2.3ms) Rendered /Users/marcel/.gem/ruby/1.8/gems/actionpack-3.2.13/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (27.7ms) Started GET "/" for 127.0.0.1 at Sun Mar 31 06:28:16 -0700 2013 Processing by LoginController#index as HTML Rendered login/index.html.erb within layouts/server (1.4ms) Completed 200 OK in 188ms (Views: 169.7ms | ActiveRecord: 0.0ms) Started GET "/user/marcel" for 127.0.0.1 at Sun Mar 31 06:28:31 -0700 2013 Processing by ServerController#user_page as HTML Parameters: {"username"=>"marcel"} Rendered text template (0.0ms) Completed 200 OK in 32ms (Views: 29.7ms | ActiveRecord: 0.0ms) Started GET "/user/marcel" for 127.0.0.1 at Sun Mar 31 06:28:53 -0700 2013 Processing by ServerController#user_page as HTML Parameters: {"username"=>"marcel"} Rendered text template (0.0ms) Completed 200 OK in 3ms (Views: 1.2ms | ActiveRecord: 0.0ms) Started GET "/assets/jquery.js?body=1" for 127.0.0.1 at Sun Mar 31 06:29:00 -0700 2013 Served asset /jquery.js - 304 Not Modified (0ms) Started GET "/consumer/start?openid_identifier=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fmarcel" for 127.0.0.1 at Sun Mar 31 06:29:10 -0700 2013 Processing by ConsumerController#start as HTML Parameters: {"openid_identifier"=>"http://localhost:3009/user/marcel"} Started GET "/user/marcel" for 127.0.0.1 at Sun Mar 31 06:29:10 -0700 2013 Processing by ServerController#user_page as application/xrds+xml Parameters: {"username"=>"marcel"} Rendered text template (0.0ms) Completed 200 OK in 1ms (Views: 0.5ms | ActiveRecord: 0.0ms) Redirected to http://localhost:3009/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fmarcel&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete Completed 302 Found in 157ms (ActiveRecord: 0.0ms) Started GET "/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fmarcel&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A3010%2Fconsumer&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete" for 127.0.0.1 at Sun Mar 31 06:29:10 -0700 2013 Processing by ServerController#index as HTML Parameters: {"openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.mode"=>"checkid_setup", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://localhost:3009/user/marcel", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.realm"=>"http://localhost:3010/consumer", "openid.claimed_id"=>"http://localhost:3009/user/marcel"} Setting last_oidreq to Rendering decide template! Rendered server/decide.html.erb within layouts/server (1.2ms) Completed 200 OK in 7ms (Views: 3.8ms | ActiveRecord: 0.0ms) Started POST "/server/decision" for 127.0.0.1 at Sun Mar 31 06:29:15 -0700 2013 Processing by ServerController#decision as HTML Parameters: {"authenticity_token"=>"5AZtwrdNxknr4gvSZ1lKzmmJqX+iJdHapyEW/jkB90M=", "yes"=>"yes"} session_id: a0903f7e5c643a4e0ee0334fcb19b4c6 session_id cookie: BAh7CyIuT3BlbklEOjpDb25zdW1lcjo6bGFzdF9yZXF1ZXN0ZWRfZW5kcG9pbnRvOiJPcGVuSUQ6Ok9wZW5JRFNlcnZpY2VFbmRwb2ludAw6DkBsb2NhbF9pZDA6GEBkaXNwbGF5X2lkZW50aWZpZXIwOg9AdHlwZV91cmlzWwgiLGh0dHA6Ly9zcGVjcy5vcGVuaWQubmV0L2F1dGgvMi4wL3NpZ25vbiIhaHR0cDovL29wZW5pZC5uZXQvc2lnbm9uLzEuMCIfaHR0cDovL29wZW5pZC5uZXQvc3JlZy8xLjA6EEB1c2VkX3lhZGlzVDoQQHNlcnZlcl91cmwiIWh0dHA6Ly9sb2NhbGhvc3Q6MzAwOS9zZXJ2ZXI6EkBjYW5vbmljYWxfaWQwOhBAY2xhaW1lZF9pZCImaHR0cDovL2xvY2FsaG9zdDozMDA5L3VzZXIvbWFyY2VsIhBfY3NyZl90b2tlbiIxNUFadHdyZE54a25yNGd2U1oxbEt6bW1KcVgraUpkSGFweUVXL2prQjkwTT0iD3Nlc3Npb25faWQiJWEwOTAzZjdlNWM2NDNhNGUwZWUwMzM0ZmNiMTliNGM2Ij1PcGVuSUQ6OkNvbnN1bWVyOjpEaXNjb3ZlcmVkU2VydmljZXM6Ok9wZW5JRDo6Q29uc3VtZXI6Om86KU9wZW5JRDo6Q29uc3VtZXI6OkRpc2NvdmVyZWRTZXJ2aWNlcwk6DkBzZXJ2aWNlc1sAOg1AY3VycmVudEAHOg9AeWFkaXNfdXJsIiZodHRwOi8vbG9jYWxob3N0OjMwMDkvdXNlci9tYXJjZWw6EkBzdGFydGluZ191cmwiJmh0dHA6Ly9sb2NhbGhvc3Q6MzAwOS91c2VyL21hcmNlbCIQbGFzdF9vaWRyZXFvOiNPcGVuSUQ6OlNlcnZlcjo6Q2hlY2tJRFJlcXVlc3QOOhFAb3BfZW5kcG9pbnQiIWh0dHA6Ly9sb2NhbGhvc3Q6MzAwOS9zZXJ2ZXI6EEB0cnVzdF9yb290IiNodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXI6DUBtZXNzYWdlbzoUT3BlbklEOjpNZXNzYWdlCDoTQG9wZW5pZF9uc191cmkiJWh0dHA6Ly9zcGVjcy5vcGVuaWQubmV0L2F1dGgvMi4wOhBAbmFtZXNwYWNlc286GU9wZW5JRDo6TmFtZXNwYWNlTWFwCDoYQG5hbWVzcGFjZV90b19hbGlhc3sGIiVodHRwOi8vc3BlY3Mub3BlbmlkLm5ldC9hdXRoLzIuMDoTbnVsbF9uYW1lc3BhY2U6GEBhbGlhc190b19uYW1lc3BhY2V7BjsbQBw6GUBpbXBsaWNpdF9uYW1lc3BhY2VzWwA6CkBhcmdzew1bB0AcIgltb2RlIhJjaGVja2lkX3NldHVwWwdAHCIPY2xhaW1lZF9pZCImaHR0cDovL2xvY2FsaG9zdDozMDA5L3VzZXIvbWFyY2VsWwc6E2JhcmVfbmFtZXNwYWNlIg9jb250cm9sbGVyIgtzZXJ2ZXJbBzsfIgthY3Rpb24iCmluZGV4WwdAHCIRYXNzb2NfaGFuZGxlIiR7SE1BQy1TSEExfXs1MTU4MmQ5NH17Y2RrbzFnPT19WwdAHCIOcmV0dXJuX3RvIixodHRwOi8vbG9jYWxob3N0OjMwMTAvY29uc3VtZXIvY29tcGxldGVbB0AcIgpyZWFsbUAaWwdAHCINaWRlbnRpdHkiJmh0dHA6Ly9sb2NhbGhvc3Q6MzAwOS91c2VyL21hcmNlbDoPQHJldHVybl90b0A0OhJAYXNzb2NfaGFuZGxlQDE6D0BpbW1lZGlhdGVGOg5AaWRlbnRpdHlAOToKQG1vZGUiEmNoZWNraWRfc2V0dXA7DEAoIgpmbGFzaG86JUFjdGlvbkRpc3BhdGNoOjpGbGFzaDo6Rmxhc2hIYXNoCToNQGZsYXNoZXN7BjoLbm90aWNlIi9EbyB5b3UgdHJ1c3QgdGhpcyBzaXRlIHdpdGggeW91ciBpZGVudGl0eT86CkB1c2VkbzoIU2V0BjoKQGhhc2h7ADoMQGNsb3NlZEY6CUBub3cw--12967a41bad9d491f50492d6caaaef2b33acb4f6 hello: last_oidreq: Redirected to http://localhost:3010/consumer/complete?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fmarcel&openid.mode=id_res&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.op_endpoint=http%3A%2F%2Flocalhost%3A3009%2Fserver&openid.response_nonce=2013-03-31T13%3A29%3A15Zsn1mhg&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete&openid.sig=XUa1u9njJyD6Ji1pcDegIvvLCpI%3D&openid.signed=assoc_handle%2Cclaimed_id%2Cidentity%2Cmode%2Cns%2Cop_endpoint%2Cresponse_nonce%2Creturn_to%2Csigned Completed 302 Found in 13ms (ActiveRecord: 0.0ms) Started GET "/consumer/complete?openid.assoc_handle=%7BHMAC-SHA1%7D%7B51582d94%7D%7Bcdko1g%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fmarcel&openid.identity=http%3A%2F%2Flocalhost%3A3009%2Fuser%2Fmarcel&openid.mode=id_res&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.op_endpoint=http%3A%2F%2Flocalhost%3A3009%2Fserver&openid.response_nonce=2013-03-31T13%3A29%3A15Zsn1mhg&openid.return_to=http%3A%2F%2Flocalhost%3A3010%2Fconsumer%2Fcomplete&openid.sig=XUa1u9njJyD6Ji1pcDegIvvLCpI%3D&openid.signed=assoc_handle%2Cclaimed_id%2Cidentity%2Cmode%2Cns%2Cop_endpoint%2Cresponse_nonce%2Creturn_to%2Csigned" for 127.0.0.1 at Sun Mar 31 06:29:15 -0700 2013 Processing by ConsumerController#complete as HTML Parameters: {"openid.sig"=>"XUa1u9njJyD6Ji1pcDegIvvLCpI=", "openid.return_to"=>"http://localhost:3010/consumer/complete", "openid.op_endpoint"=>"http://localhost:3009/server", "openid.mode"=>"id_res", "openid.response_nonce"=>"2013-03-31T13:29:15Zsn1mhg", "openid.ns"=>"http://specs.openid.net/auth/2.0", "openid.identity"=>"http://localhost:3009/user/marcel", "openid.signed"=>"assoc_handle,claimed_id,identity,mode,ns,op_endpoint,response_nonce,return_to,signed", "openid.assoc_handle"=>"{HMAC-SHA1}{51582d94}{cdko1g==}", "openid.claimed_id"=>"http://localhost:3009/user/marcel"} Redirected to http://localhost:3010/consumer Completed 302 Found in 12ms (ActiveRecord: 0.0ms) Started GET "/consumer" for 127.0.0.1 at Sun Mar 31 06:29:15 -0700 2013 Processing by ConsumerController#index as HTML Rendered consumer/index.html.erb within layouts/application (1.4ms) Completed 200 OK in 9ms (Views: 8.3ms | ActiveRecord: 0.0ms) Started GET "/assets/application.css?body=1" for 127.0.0.1 at Sun Mar 31 06:29:15 -0700 2013 Served asset /application.css - 304 Not Modified (0ms) Started GET "/assets/application.js?body=1" for 127.0.0.1 at Sun Mar 31 06:29:15 -0700 2013 Served asset /application.js - 304 Not Modified (0ms) Started GET "/assets/jquery.js?body=1" for 127.0.0.1 at Sun Mar 31 06:29:15 -0700 2013 Served asset /jquery.js - 304 Not Modified (0ms) ================================================ FILE: examples/rails_openid/public/404.html ================================================ The page you were looking for doesn't exist (404)

The page you were looking for doesn't exist.

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

================================================ FILE: examples/rails_openid/public/422.html ================================================ The change you wanted was rejected (422)

The change you wanted was rejected.

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

================================================ FILE: examples/rails_openid/public/500.html ================================================ We're sorry, but something went wrong (500)

We're sorry, but something went wrong.

================================================ FILE: examples/rails_openid/public/dispatch.cgi ================================================ #!/usr/bin/ruby1.8 #!/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 ================================================ FILE: examples/rails_openid/public/dispatch.fcgi ================================================ #!/usr/bin/ruby1.8 #!/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! ================================================ FILE: examples/rails_openid/public/dispatch.rb ================================================ #!/usr/bin/ruby1.8 #!/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 ================================================ FILE: examples/rails_openid/public/javascripts/application.js ================================================ // Place your application-specific JavaScript functions and classes here // This file is automatically included by javascript_include_tag :defaults ================================================ FILE: examples/rails_openid/public/javascripts/controls.js ================================================ // Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) // (c) 2005-2008 Ivan Krstic (http://blogs.law.harvard.edu/ivan) // (c) 2005-2008 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, ''); 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("
  • " + elem.substr(0, entry.length) + "" + elem.substr(entry.length) + "
  • "); 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("
  • " + elem.substr(0, foundPos) + "" + elem.substr(foundPos, entry.length) + "" + elem.substr( foundPos + entry.length) + "
  • "); 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 "
      " + ret.join('') + "
    "; } }, options || { }); } }); // AJAX in-place editor and collection editor // Full rewrite by Christophe Porteneuve (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.unescapeHTML(); }, 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)); } }); ================================================ FILE: examples/rails_openid/public/javascripts/dragdrop.js ================================================ // Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) // (c) 2005-2008 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._originallyAbsolute = (this.element.getStyle('position') == 'absolute'); if (!this._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._originallyAbsolute) Position.relativize(this.element); delete this._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){ element = $(element); var s = Sortable.sortables[element.id]; 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')]; }; ================================================ FILE: examples/rails_openid/public/javascripts/effects.js ================================================ // Copyright (c) 2005-2008 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) + .5; }, reverse: function(pos) { return 1-pos; }, flicker: function(pos) { var pos = ((-Math.cos(pos*Math.PI)/4) + .75) + Math.random()/4; return pos > 1 ? 1 : pos; }, wobble: function(pos) { return (-Math.cos(pos*Math.PI*(9*pos))/2) + .5; }, pulse: function(pos, pulses) { return (-Math.cos((pos*((pulses||5)-.5)*2)*Math.PI)/2) + .5; }, 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= 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.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(); if (options.offset) elementOffsets[1] += options.offset; return new Effect.Tween(null, scrollOffsets.top, 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] || { }, oldOpacity = element.getInlineOpacity(), transition = options.transition || Effect.Transitions.linear, reverser = function(pos){ return 1 - transition((-Math.cos((pos*(options.pulses||5)*2)*Math.PI)/2) + .5); }; 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 = '
    '; 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(results, property) { results[property] = css[property]; return results; }); if (!styles.opacity) styles.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); ================================================ FILE: examples/rails_openid/public/javascripts/prototype.js ================================================ /* Prototype JavaScript framework, version 1.6.0.3 * (c) 2005-2008 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.3', Browser: { IE: !!(window.attachEvent && navigator.userAgent.indexOf('Opera') === -1), Opera: navigator.userAgent.indexOf('Opera') > -1, 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, SelectorsAPI: !!document.querySelector, ElementExtensions: !!window.HTMLElement, SpecificElementExtensions: document.createElement('div')['__proto__'] && document.createElement('div')['__proto__'] !== document.createElement('form')['__proto__'] }, ScriptFragment: ']*>([\\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 = (function(m) { return function() { return ancestor[m].apply(this, arguments) }; })(property).wrap(method); value.valueOf = method.valueOf.bind(method); value.toString = method.toString.bind(method); } 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() : String(object); } 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 != null && typeof object == "object" && 'splice' in object && 'join' in object; }, 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] .replace(/\s+/g, '').split(','); 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); }, defer: function() { var args = [0.01].concat($A(arguments)); return this.delay.apply(this, args); }, 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))); }; } }); 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,'&').replace(//g,'>'); }, unescapeHTML: function() { return this.stripTags().replace(/&/g,'&').replace(/</g,'<').replace(/>/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('') }); String.prototype.escapeHTML.div.appendChild(String.prototype.escapeHTML.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); }); } }); Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; var $break = { }; var Enumerable = { each: function(iterator, context) { var index = 0; try { this._each(function(value) { iterator.call(context, value, index++); }); } catch (e) { if (e != $break) throw e; } return this; }, eachSlice: function(number, iterator, context) { var index = -number, slices = [], array = this.toArray(); if (number < 1) return array; while ((index += number) < array.length) slices.push(array.slice(index, index+number)); return slices.collect(iterator, context); }, all: function(iterator, context) { iterator = iterator || Prototype.K; var result = true; this.each(function(value, index) { result = result && !!iterator.call(context, value, index); if (!result) throw $break; }); return result; }, any: function(iterator, context) { iterator = iterator || Prototype.K; var result = false; this.each(function(value, index) { if (result = !!iterator.call(context, value, index)) throw $break; }); return result; }, collect: function(iterator, context) { iterator = iterator || Prototype.K; var results = []; this.each(function(value, index) { results.push(iterator.call(context, value, index)); }); return results; }, detect: function(iterator, context) { var result; this.each(function(value, index) { if (iterator.call(context, value, index)) { result = value; throw $break; } }); return result; }, findAll: function(iterator, context) { var results = []; this.each(function(value, index) { if (iterator.call(context, value, index)) results.push(value); }); return results; }, grep: function(filter, iterator, context) { iterator = iterator || Prototype.K; var results = []; if (Object.isString(filter)) filter = new RegExp(filter); this.each(function(value, index) { if (filter.match(value)) results.push(iterator.call(context, 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) { this.each(function(value, index) { memo = iterator.call(context, 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 || Prototype.K; var result; this.each(function(value, index) { value = iterator.call(context, value, index); if (result == null || value >= result) result = value; }); return result; }, min: function(iterator, context) { iterator = iterator || Prototype.K; var result; this.each(function(value, index) { value = iterator.call(context, value, index); if (result == null || value < result) result = value; }); return result; }, partition: function(iterator, context) { iterator = iterator || Prototype.K; var trues = [], falses = []; this.each(function(value, index) { (iterator.call(context, 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) { var results = []; this.each(function(value, index) { if (!iterator.call(context, value, index)) results.push(value); }); return results; }, sortBy: function(iterator, context) { return this.map(function(value, index) { return { value: value, criteria: iterator.call(context, 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 '#'; } }; 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 || 0, results = new Array(length); while (length--) results[length] = iterable[length]; return results; } if (Prototype.Browser.WebKit) { $A = function(iterable) { if (!iterable) return []; // In Safari, only use the `toArray` method if it's not a NodeList. // A NodeList is a function, has an function `item` property, and a numeric // `length` property. Adapted from Google Doctype. if (!(typeof iterable === 'function' && typeof iterable.length === 'number' && typeof iterable.item === 'function') && iterable.toArray) return iterable.toArray(); var length = iterable.length || 0, 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, context) { $R(0, this, true).each(iterator, context); 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) { // simulating poorly supported hasOwnProperty if (this._object[key] !== Object.prototype[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.inject([], function(results, pair) { var key = encodeURIComponent(pair.key), values = pair.value; if (values && typeof values == 'object') { if (Object.isArray(values)) return results.concat(values.map(toQueryPair.curry(key))); } else results.push(toQueryPair(key, values)); return results; }).join('&'); }, inspect: function() { return '#'; }, 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 && this.isSameOrigin() && 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; } }, isSameOrigin: function() { var m = this.url.match(/^\s*https?:\/\/[^\/]*/); return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({ protocol: location.protocol, domain: document.domain, port: location.port ? ':' + location.port : '' })); }, getHeader: function(name) { try { return this.transport.getResponseHeader(name) || null; } 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 || !this.request.isSameOrigin()); } 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 || !this.request.isSameOrigin()); } 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 || { }); if (element) this.Element.prototype = element.prototype; }).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 = $(element); element.style.display = 'none'; return element; }, show: function(element) { element = $(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, insert, tagName, childNodes; for (var position in insertions) { content = insertions[position]; position = position.toLowerCase(); insert = Element._insertionTranslations[position]; if (content && content.toElement) content = content.toElement(); if (Object.isElement(content)) { insert(element, content); continue; } content = Object.toHTML(content); tagName = ((position == 'before' || position == 'after') ? element.parentNode : element).tagName.toUpperCase(); childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); if (position == 'top' || position == 'after') childNodes.reverse(); childNodes.each(insert.curry(element)); 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).select("*"); }, 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 Object.isNumber(expression) ? ancestors[expression] : Selector.findElement(ancestors, expression, index); }, down: function(element, expression, index) { element = $(element); if (arguments.length == 1) return element.firstDescendant(); return Object.isNumber(expression) ? element.descendants()[expression] : Element.select(element, expression)[index || 0]; }, previous: function(element, expression, index) { element = $(element); if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element)); var previousSiblings = element.previousSiblings(); return Object.isNumber(expression) ? previousSiblings[expression] : Selector.findElement(previousSiblings, expression, index); }, next: function(element, expression, index) { element = $(element); if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element)); var nextSiblings = element.nextSiblings(); return Object.isNumber(expression) ? nextSiblings[expression] : Selector.findElement(nextSiblings, expression, index); }, 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); if (element.compareDocumentPosition) return (element.compareDocumentPosition(ancestor) & 8) === 8; if (ancestor.contains) return ancestor.contains(element) && ancestor !== element; while (element = element.parentNode) if (element == ancestor) 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 || value == 'auto') { 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 (Prototype.Browser.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.toUpperCase() == 'BODY') break; var p = Element.getStyle(element, 'position'); if (p !== 'static') break; } } while (element); return Element._returnOffset(valueL, valueT); }, absolutize: function(element) { element = $(element); if (element.getStyle('position') == 'absolute') return element; // 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 element; // 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 && (element.tagName.toUpperCase() == '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 (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) { // IE doesn't report offsets correctly for static elements, so we change them // to "relative" to get the values, then change them back. Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap( function(proceed, element) { element = $(element); // IE throws an error if element is not in document try { element.offsetParent } catch(e) { return $(document.body) } 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; } ); $w('positionedOffset viewportOffset').each(function(method) { Element.Methods[method] = Element.Methods[method].wrap( function(proceed, element) { element = $(element); try { element.offsetParent } catch(e) { return Element._returnOffset(0,0) } var position = element.getStyle('position'); if (position !== 'static') return proceed(element); // Trigger hasLayout on the offset parent so that IE6 reports // accurate offsetTop and offsetLeft values for position: fixed. var offsetParent = element.getOffsetParent(); if (offsetParent && offsetParent.getStyle('position') === 'fixed') offsetParent.setStyle({ zoom: 1 }); element.setStyle({ position: 'relative' }); var value = proceed(element); element.setStyle({ position: position }); return value; } ); }); Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap( function(proceed, element) { try { element.offsetParent } catch(e) { return Element._returnOffset(0,0) } return proceed(element); } ); 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.extend({ cellpadding: 'cellPadding', cellspacing: 'cellSpacing' }, 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 frameBorder').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.toUpperCase() == '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 ('outerHTML' in document.createElement('div')) { 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]; if (t) { div.innerHTML = t[0] + html + t[1]; t[2].times(function() { div = div.firstChild }); } else div.innerHTML = html; return $A(div.childNodes); }; Element._insertionTranslations = { before: function(element, node) { element.parentNode.insertBefore(node, element); }, top: function(element, node) { element.insertBefore(node, element.firstChild); }, bottom: function(element, node) { element.appendChild(node); }, after: function(element, node) { element.parentNode.insertBefore(node, element.nextSibling); }, tags: { TABLE: ['
    Site:<%= @oidreq.trust_root %>
    ', '
    ', 1], TBODY: ['', '
    ', 2], TR: ['', '
    ', 3], TD: ['
    ', '
    ', 4], SELECT: ['', 1] } }; (function() { 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.toUpperCase(), 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 = { }, B = Prototype.Browser; $w('width height').each(function(d) { var D = d.capitalize(); if (B.WebKit && !document.evaluate) { // Safari <3.0 needs self.innerWidth/Height dimensions[d] = self['inner' + D]; } else if (B.Opera && parseFloat(window.opera.version()) < 9.5) { // Opera <9.5 needs document.body.clientWidth/Height dimensions[d] = document.body['client' + D] } else { dimensions[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(); if (this.shouldUseSelectorsAPI()) { this.mode = 'selectorsAPI'; } else if (this.shouldUseXPath()) { this.mode = 'xpath'; this.compileXPathMatcher(); } else { this.mode = "normal"; 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(e)) return false; return true; }, shouldUseSelectorsAPI: function() { if (!Prototype.BrowserFeatures.SelectorsAPI) return false; if (!Selector._div) Selector._div = new Element('div'); // Make sure the browser treats the selector as valid. Test on an // isolated element to minimize cost of this check. try { Selector._div.querySelector(this.expression); } catch(e) { return false; } return true; }, compileMatcher: function() { 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; var e = this.expression, results; switch (this.mode) { case 'selectorsAPI': // querySelectorAll queries document-wide, then filters to descendants // of the context element. That's not what we want. // Add an explicit context to the selector if necessary. if (root !== document) { var oldId = root.id, id = $(root).identify(); e = "#" + id + " " + e; } results = $A(root.querySelectorAll(e)).map(Element.extend); root.id = oldId; return results; case 'xpath': return document._getElementsByXPath(this.xpath, root); default: 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 "#"; } }); 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)]", 'checked': "[@checked]", 'disabled': "[(@disabled) and (@type!='hidden')]", 'enabled': "[not(@disabled) and (@type!='hidden')]", '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); c = false;', attr: function(m) { m[3] = (m[5] || m[6]); return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); 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]+:)?[\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 nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]); } }, 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) { var _true = Prototype.emptyFunction; for (var i = 0, node; node = nodes[i]; i++) node._countedByPrototype = _true; return nodes; }, unmark: function(nodes) { for (var i = 0, node; node = nodes[i]; i++) node._countedByPrototype = 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._countedByPrototype = Prototype.emptyFunction; 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._countedByPrototype)) node.nodeIndex = j++; } } else { for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++) if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) 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])._countedByPrototype) { n._countedByPrototype = Prototype.emptyFunction; 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) { var uTagName = 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() === uTagName) 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, combinator) { if (!nodes) nodes = root.getElementsByTagName("*"); if (nodes && combinator) nodes = this[combinator](nodes); 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, combinator) { if (!nodes) nodes = root.getElementsByTagName("*"); if (nodes && combinator) nodes = this[combinator](nodes); 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._countedByPrototype) { 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) 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._countedByPrototype) 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 && (!node.type || node.type !== 'hidden')) 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 == v || nv && nv.startsWith(v); }, '$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); }, '*=': function(nv, v) { return nv == v || nv && nv.include(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() + '-'); } }, split: function(expression) { var expressions = []; expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) { expressions.push(m[1].strip()); }); return expressions; }, matchElements: function(elements, expression) { var matches = $$(expression), h = Selector.handlers; h.mark(matches); for (var i = 0, results = [], element; element = elements[i]; i++) if (element._countedByPrototype) 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) { expressions = Selector.split(expressions.join(',')); 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) { Object.extend(Selector.handlers, { // IE returns comment nodes on getElementsByTagName("*"). // Filter them out. concat: function(a, b) { for (var i = 0, node; node = b[i]; i++) if (node.tagName !== "!") a.push(node); return a; }, // IE improperly serializes _countedByPrototype in (inner|outer)HTML. unmark: function(nodes) { for (var i = 0, node; node = nodes[i]; i++) node.removeAttribute('_countedByPrototype'); return nodes; } }); } 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 != 'file' && (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.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, value) { if (Object.isUndefined(value)) return this[element.type == 'select-one' ? 'selectOne' : 'selectMany'](element); else { var opt, currentValue, single = !Object.isArray(value); for (var i = 0, length = element.length; i < length; i++) { opt = element.options[i]; currentValue = this.optionValue(opt); if (single) { if (currentValue == value) { opt.selected = true; return; } } else opt.selected = value.include(currentValue); } } }, 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) { event = Event.extend(event); var node = event.target, type = event.type, currentTarget = event.currentTarget; if (currentTarget && currentTarget.tagName) { // Firefox screws up the "click" event when moving between radio buttons // via arrow keys. It also screws up the "load" and "error" events on images, // reporting the document as the target instead of the original image. if (type === 'load' || type === 'error' || (type === 'click' && currentTarget.tagName.toLowerCase() === 'input' && currentTarget.type === 'radio')) node = currentTarget; } if (node.nodeType == Node.TEXT_NODE) node = node.parentNode; return Element.extend(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) { var docElement = document.documentElement, body = document.body || { scrollLeft: 0, scrollTop: 0 }; return { x: event.pageX || (event.clientX + (docElement.scrollLeft || body.scrollLeft) - (docElement.clientLeft || 0)), y: event.pageY || (event.clientY + (docElement.scrollTop || body.scrollTop) - (docElement.clientTop || 0)) }; }, 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._prototypeEventID) return element._prototypeEventID[0]; arguments.callee.id = arguments.callee.id || 1; return element._prototypeEventID = [++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; } // Internet Explorer needs to remove event handlers on page unload // in order to avoid memory leaks. if (window.attachEvent) { window.attachEvent("onunload", destroyCache); } // Safari has a dummy event handler on page unload so that it won't // use its bfcache. Safari <= 3.1 has an issue with restoring the "document" // object when page is returned to via the back button using its bfcache. if (Prototype.Browser.WebKit) { window.addEventListener('unload', Prototype.emptyFunction, false); } 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; var event; if (document.createEvent) { event = document.createEvent("HTMLEvents"); event.initEvent("dataavailable", true, true); } else { 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(), loaded: false }); (function() { /* Support for the DOMContentLoaded event is based on work by Dan Webb, Matthias Miller, Dean Edwards and John Resig. */ var timer; function fireContentLoadedEvent() { if (document.loaded) return; if (timer) window.clearInterval(timer); document.fire("dom:loaded"); document.loaded = 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(" " end ESCAPE_TABLE = { '&' => '&', '<' => '<', '>' => '>', '"' => '"', "'" => ''' } # Modified from ERb's html_encode def Util.html_encode(str) str.to_s.gsub(/[&<>"']/) {|s| ESCAPE_TABLE[s] } end end end ================================================ FILE: lib/openid/version.rb ================================================ module OpenID VERSION = "2.9.2" end ================================================ FILE: lib/openid/yadis/accept.rb ================================================ module OpenID module Yadis # Generate an accept header value # # [str or (str, float)] -> str def self.generate_accept_header(*elements) parts = [] elements.each { |element| if element.is_a?(String) qs = "1.0" mtype = element else mtype, q = element q = q.to_f if q > 1 or q <= 0 raise ArgumentError.new("Invalid preference factor: #{q}") end qs = sprintf("%0.1f", q) end parts << [qs, mtype] } parts.sort! chunks = [] parts.each { |q, mtype| if q == '1.0' chunks << mtype else chunks << sprintf("%s; q=%s", mtype, q) end } return chunks.join(', ') end def self.parse_accept_header(value) # Parse an accept header, ignoring any accept-extensions # # returns a list of tuples containing main MIME type, MIME # subtype, and quality markdown. # # str -> [(str, str, float)] chunks = value.split(',', -1).collect { |v| v.strip } accept = [] chunks.each { |chunk| parts = chunk.split(";", -1).collect { |s| s.strip } mtype = parts.shift if mtype.index('/').nil? # This is not a MIME type, so ignore the bad data next end main, sub = mtype.split('/', 2) q = nil parts.each { |ext| if !ext.index('=').nil? k, v = ext.split('=', 2) if k == 'q' q = v.to_f end end } q = 1.0 if q.nil? accept << [q, main, sub] } accept.sort! accept.reverse! return accept.collect { |q, main, sub| [main, sub, q] } end def self.match_types(accept_types, have_types) # Given the result of parsing an Accept: header, and the # available MIME types, return the acceptable types with their # quality markdowns. # # For example: # # >>> acceptable = parse_accept_header('text/html, text/plain; q=0.5') # >>> matchTypes(acceptable, ['text/plain', 'text/html', 'image/jpeg']) # [('text/html', 1.0), ('text/plain', 0.5)] # # Type signature: ([(str, str, float)], [str]) -> [(str, float)] if accept_types.nil? or accept_types == [] # Accept all of them default = 1 else default = 0 end match_main = {} match_sub = {} accept_types.each { |main, sub, q| if main == '*' default = [default, q].max next elsif sub == '*' match_main[main] = [match_main.fetch(main, 0), q].max else match_sub[[main, sub]] = [match_sub.fetch([main, sub], 0), q].max end } accepted_list = [] order_maintainer = 0 have_types.each { |mtype| main, sub = mtype.split('/', 2) if match_sub.member?([main, sub]) q = match_sub[[main, sub]] else q = match_main.fetch(main, default) end if q != 0 accepted_list << [1 - q, order_maintainer, q, mtype] order_maintainer += 1 end } accepted_list.sort! return accepted_list.collect { |_, _, q, mtype| [mtype, q] } end def self.get_acceptable(accept_header, have_types) # Parse the accept header and return a list of available types # in preferred order. If a type is unacceptable, it will not be # in the resulting list. # # This is a convenience wrapper around matchTypes and # parse_accept_header # # (str, [str]) -> [str] accepted = self.parse_accept_header(accept_header) preferred = self.match_types(accepted, have_types) return preferred.collect { |mtype, _| mtype } end end end ================================================ FILE: lib/openid/yadis/constants.rb ================================================ require 'openid/yadis/accept' module OpenID module Yadis YADIS_HEADER_NAME = 'X-XRDS-Location' YADIS_CONTENT_TYPE = 'application/xrds+xml' # A value suitable for using as an accept header when performing # YADIS discovery, unless the application has special requirements YADIS_ACCEPT_HEADER = generate_accept_header( ['text/html', 0.3], ['application/xhtml+xml', 0.5], [YADIS_CONTENT_TYPE, 1.0] ) end end ================================================ FILE: lib/openid/yadis/discovery.rb ================================================ require 'openid/util' require 'openid/fetchers' require 'openid/yadis/constants' require 'openid/yadis/parsehtml' module OpenID # Raised when a error occurs in the discovery process class DiscoveryFailure < OpenIDError attr_accessor :identity_url, :http_response def initialize(message, http_response) super(message) @identity_url = nil @http_response = http_response end end module Yadis # Contains the result of performing Yadis discovery on a URI class DiscoveryResult # The result of following redirects from the request_uri attr_accessor :normalize_uri # The URI from which the response text was returned (set to # nil if there was no XRDS document found) attr_accessor :xrds_uri # The content-type returned with the response_text attr_accessor :content_type # The document returned from the xrds_uri attr_accessor :response_text attr_accessor :request_uri, :normalized_uri def initialize(request_uri) # Initialize the state of the object # # sets all attributes to None except the request_uri @request_uri = request_uri @normalized_uri = nil @xrds_uri = nil @content_type = nil @response_text = nil end # Was the Yadis protocol's indirection used? def used_yadis_location? return @normalized_uri != @xrds_uri end # Is the response text supposed to be an XRDS document? def is_xrds return (used_yadis_location?() or @content_type == YADIS_CONTENT_TYPE) end end # Discover services for a given URI. # # uri: The identity URI as a well-formed http or https URI. The # well-formedness and the protocol are not checked, but the # results of this function are undefined if those properties do # not hold. # # returns a DiscoveryResult object # # Raises DiscoveryFailure when the HTTP response does not have # a 200 code. def self.discover(uri) result = DiscoveryResult.new(uri) begin resp = OpenID.fetch(uri, nil, {'Accept' => YADIS_ACCEPT_HEADER}) rescue Exception raise DiscoveryFailure.new("Failed to fetch identity URL #{uri} : #{$!}", $!) end if resp.code != "200" and resp.code != "206" raise DiscoveryFailure.new( "HTTP Response status from identity URL host is not \"200\"."\ "Got status #{resp.code.inspect} for #{resp.final_url}", resp) end # Note the URL after following redirects result.normalized_uri = resp.final_url # Attempt to find out where to go to discover the document or if # we already have it result.content_type = resp['content-type'] result.xrds_uri = self.where_is_yadis?(resp) if result.xrds_uri and result.used_yadis_location? begin resp = OpenID.fetch(result.xrds_uri) rescue raise DiscoveryFailure.new("Failed to fetch Yadis URL #{result.xrds_uri} : #{$!}", $!) end if resp.code != "200" and resp.code != "206" exc = DiscoveryFailure.new( "HTTP Response status from Yadis host is not \"200\". " + "Got status #{resp.code.inspect} for #{resp.final_url}", resp) exc.identity_url = result.normalized_uri raise exc end result.content_type = resp['content-type'] end result.response_text = resp.body return result end # Given a HTTPResponse, return the location of the Yadis # document. # # May be the URL just retrieved, another URL, or None, if I # can't find any. # # [non-blocking] def self.where_is_yadis?(resp) # Attempt to find out where to go to discover the document or if # we already have it content_type = resp['content-type'] # According to the spec, the content-type header must be an # exact match, or else we have to look for an indirection. if (!content_type.nil? and !content_type.to_s.empty? and content_type.split(';', 2)[0].downcase == YADIS_CONTENT_TYPE) return resp.final_url else # Try the header yadis_loc = resp[YADIS_HEADER_NAME.downcase] if yadis_loc.nil? # Parse as HTML if the header is missing. # # XXX: do we want to do something with content-type, like # have a whitelist or a blacklist (for detecting that it's # HTML)? yadis_loc = Yadis.html_yadis_location(resp.body) end end return yadis_loc end end end ================================================ FILE: lib/openid/yadis/filters.rb ================================================ # This file contains functions and classes used for extracting # endpoint information out of a Yadis XRD file using the REXML # XML parser. # module OpenID module Yadis class BasicServiceEndpoint attr_reader :type_uris, :yadis_url, :uri, :service_element # Generic endpoint object that contains parsed service # information, as well as a reference to the service element # from which it was generated. If there is more than one # xrd:Type or xrd:URI in the xrd:Service, this object represents # just one of those pairs. # # This object can be used as a filter, because it implements # fromBasicServiceEndpoint. # # The simplest kind of filter you can write implements # fromBasicServiceEndpoint, which takes one of these objects. def initialize(yadis_url, type_uris, uri, service_element) @type_uris = type_uris @yadis_url = yadis_url @uri = uri @service_element = service_element end # Query this endpoint to see if it has any of the given type # URIs. This is useful for implementing other endpoint classes # that e.g. need to check for the presence of multiple # versions of a single protocol. def match_types(type_uris) return @type_uris & type_uris end # Trivial transform from a basic endpoint to itself. This # method exists to allow BasicServiceEndpoint to be used as a # filter. # # If you are subclassing this object, re-implement this function. def self.from_basic_service_endpoint(endpoint) return endpoint end # A hack to make both this class and its instances respond to # this message since Ruby doesn't support static methods. def from_basic_service_endpoint(endpoint) return self.class.from_basic_service_endpoint(endpoint) end end # Take a list of basic filters and makes a filter that # transforms the basic filter into a top-level filter. This is # mostly useful for the implementation of make_filter, which # should only be needed for special cases or internal use by # this library. # # This object is useful for creating simple filters for services # that use one URI and are specified by one Type (we expect most # Types will fit this paradigm). # # Creates a BasicServiceEndpoint object and apply the filter # functions to it until one of them returns a value. class TransformFilterMaker attr_reader :filter_procs # Initialize the filter maker's state # # filter_functions are the endpoint transformer # Procs to apply to the basic endpoint. These are called in # turn until one of them does not return nil, and the result # of that transformer is returned. def initialize(filter_procs) @filter_procs = filter_procs end # Returns an array of endpoint objects produced by the # filter procs. def get_service_endpoints(yadis_url, service_element) endpoints = [] # Do an expansion of the service element by xrd:Type and # xrd:URI Yadis::expand_service(service_element).each { |type_uris, uri, _| # Create a basic endpoint object to represent this # yadis_url, Service, Type, URI combination endpoint = BasicServiceEndpoint.new( yadis_url, type_uris, uri, service_element) e = apply_filters(endpoint) if !e.nil? endpoints << e end } return endpoints end def apply_filters(endpoint) # Apply filter procs to an endpoint until one of them returns # non-nil. @filter_procs.each { |filter_proc| e = filter_proc.call(endpoint) if !e.nil? # Once one of the filters has returned an endpoint, do not # apply any more. return e end } return nil end end class CompoundFilter attr_reader :subfilters # Create a new filter that applies a set of filters to an # endpoint and collects their results. def initialize(subfilters) @subfilters = subfilters end # Generate all endpoint objects for all of the subfilters of # this filter and return their concatenation. def get_service_endpoints(yadis_url, service_element) endpoints = [] @subfilters.each { |subfilter| endpoints += subfilter.get_service_endpoints(yadis_url, service_element) } return endpoints end end # Exception raised when something is not able to be turned into a # filter @@filter_type_error = TypeError.new( 'Expected a filter, an endpoint, a callable or a list of any of these.') # Convert a filter-convertable thing into a filter # # parts should be a filter, an endpoint, a callable, or a list of # any of these. def self.make_filter(parts) # Convert the parts into a list, and pass to mk_compound_filter if parts.nil? parts = [BasicServiceEndpoint] end if parts.is_a?(Array) return mk_compound_filter(parts) else return mk_compound_filter([parts]) end end # Create a filter out of a list of filter-like things # # Used by make_filter # # parts should be a list of things that can be passed to make_filter def self.mk_compound_filter(parts) if !parts.respond_to?('each') raise TypeError, "#{parts.inspect} is not iterable" end # Separate into a list of callables and a list of filter objects transformers = [] filters = [] parts.each { |subfilter| if !subfilter.is_a?(Array) # If it's not an iterable if subfilter.respond_to?('get_service_endpoints') # It's a full filter filters << subfilter elsif subfilter.respond_to?('from_basic_service_endpoint') # It's an endpoint object, so put its endpoint conversion # attribute into the list of endpoint transformers transformers << subfilter.method('from_basic_service_endpoint') elsif subfilter.respond_to?('call') # It's a proc, so add it to the list of endpoint # transformers transformers << subfilter else raise @@filter_type_error end else filters << mk_compound_filter(subfilter) end } if transformers.length > 0 filters << TransformFilterMaker.new(transformers) end if filters.length == 1 return filters[0] else return CompoundFilter.new(filters) end end end end ================================================ FILE: lib/openid/yadis/htmltokenizer.rb ================================================ # = HTMLTokenizer # # Author:: Ben Giddings (mailto:bg-rubyforge@infofiend.com) # Copyright:: Copyright (c) 2004 Ben Giddings # License:: Distributes under the same terms as Ruby # # # This is a partial port of the functionality behind Perl's TokeParser # Provided a page it progressively returns tokens from that page # # $Id: htmltokenizer.rb,v 1.7 2005/06/07 21:05:53 merc Exp $ # # A class to tokenize HTML. # # Example: # # page = " # # This is the title # # # #

    This is the header

    #

    # This is the paragraph, it contains # links, # images
#        are
#        really cool. Ok, here is some more text and # another link. #

    # # # " # toke = HTMLTokenizer.new(page) # # assert("

    " == toke.getTag("h1", "h2", "h3").to_s.downcase) # assert(HTMLTag.new("") == toke.getTag("IMG", "A")) # assert("links" == toke.getTrimmedText) # assert(toke.getTag("IMG", "A").attr_hash['optional']) # assert("_blank" == toke.getTag("IMG", "A").attr_hash['target']) # class HTMLTokenizer @@version = 1.0 # Get version of HTMLTokenizer lib def self.version @@version end attr_reader :page # Create a new tokenizer, based on the content, used as a string. def initialize(content) @page = content.to_s @cur_pos = 0 end # Reset the parser, setting the current position back at the stop def reset @cur_pos = 0 end # Look at the next token, but don't actually grab it def peekNextToken if @cur_pos == @page.length then return nil end if ?< == @page[@cur_pos] # Next token is a tag of some kind if '!--' == @page[(@cur_pos + 1), 3] # Token is a comment tag_end = @page.index('-->', (@cur_pos + 1)) if tag_end.nil? raise HTMLTokenizerError, "No end found to started comment:\n#{@page[@cur_pos,80]}" end # p @page[@cur_pos .. (tag_end+2)] HTMLComment.new(@page[@cur_pos .. (tag_end + 2)]) else # Token is a html tag tag_end = @page.index('>', (@cur_pos + 1)) if tag_end.nil? raise HTMLTokenizerError, "No end found to started tag:\n#{@page[@cur_pos,80]}" end # p @page[@cur_pos .. tag_end] HTMLTag.new(@page[@cur_pos .. tag_end]) end else # Next token is text text_end = @page.index('<', @cur_pos) text_end = text_end.nil? ? -1 : (text_end - 1) # p @page[@cur_pos .. text_end] HTMLText.new(@page[@cur_pos .. text_end]) end end # Get the next token, returns an instance of # * HTMLText # * HTMLToken # * HTMLTag def getNextToken token = peekNextToken if token # @page = @page[token.raw.length .. -1] # @page.slice!(0, token.raw.length) @cur_pos += token.raw.length end #p token #print token.raw return token end # Get a tag from the specified set of desired tags. # For example: # foo = toke.getTag("h1", "h2", "h3") # Will return the next header tag encountered. def getTag(*sought_tags) sought_tags.collect! {|elm| elm.downcase} while (tag = getNextToken) if tag.kind_of?(HTMLTag) and (0 == sought_tags.length or sought_tags.include?(tag.tag_name)) break end end tag end # Get all the text between the current position and the next tag # (if specified) or a specific later tag def getText(until_tag = nil) if until_tag.nil? if ?< == @page[@cur_pos] # Next token is a tag, not text "" else # Next token is text getNextToken.text end else ret_str = "" while (tag = peekNextToken) if tag.kind_of?(HTMLTag) and tag.tag_name == until_tag break end if ("" != tag.text) ret_str << (tag.text + " ") end getNextToken end ret_str end end # Like getText, but squeeze all whitespace, getting rid of # leading and trailing whitespace, and squeezing multiple # spaces into a single space. def getTrimmedText(until_tag = nil) getText(until_tag).strip.gsub(/\s+/m, " ") end end class HTMLTokenizerError < Exception end # The parent class for all three types of HTML tokens class HTMLToken attr_accessor :raw # Initialize the token based on the raw text def initialize(text) @raw = text end # By default, return exactly the string used to create the text def to_s raw end # By default tokens have no text representation def text "" end def trimmed_text text.strip.gsub(/\s+/m, " ") end # Compare to another based on the raw source def ==(other) raw == other.to_s end end # Class representing text that isn't inside a tag class HTMLText < HTMLToken def text raw end end # Class representing an HTML comment class HTMLComment < HTMLToken attr_accessor :contents def initialize(text) super(text) temp_arr = text.scan(/^$/m) if temp_arr[0].nil? raise HTMLTokenizerError, "Text passed to HTMLComment.initialize is not a comment" end @contents = temp_arr[0][0] end end # Class representing an HTML tag class HTMLTag < HTMLToken attr_reader :end_tag, :tag_name def initialize(text) super(text) if ?< != text[0] or ?> != text[-1] raise HTMLTokenizerError, "Text passed to HTMLComment.initialize is not a comment" end @attr_hash = Hash.new @raw = text tag_name = text.scan(/[\w:-]+/)[0] if tag_name.nil? raise HTMLTokenizerError, "Error, tag is nil: #{tag_name}" end if ?/ == text[1] # It's an end tag @end_tag = true @tag_name = '/' + tag_name.downcase else @end_tag = false @tag_name = tag_name.downcase end @hashed = false end # Retrieve a hash of all the tag's attributes. # Lazily done, so that if you don't look at a tag's attributes # things go quicker def attr_hash # Lazy initialize == don't build the hash until it's needed if !@hashed if !@end_tag # Get the attributes attr_arr = @raw.scan(/<[\w:-]+\s+(.*?)\/?>/m)[0] if attr_arr.kind_of?(Array) # Attributes found, parse them attrs = attr_arr[0] attr_arr = attrs.scan(/\s*([\w:-]+)(?:\s*=\s*("[^"]*"|'[^']*'|([^"'>][^\s>]*)))?/m) # clean up the array by: # * setting all nil elements to true # * removing enclosing quotes attr_arr.each { |item| val = if item[1].nil? item[0] elsif '"'[0] == item[1][0] or '\''[0] == item[1][0] item[1][1 .. -2] else item[1] end @attr_hash[item[0].downcase] = val } end end @hashed = true end #p self @attr_hash end # Get the 'alt' text for a tag, if it exists, or an empty string otherwise def text if !end_tag case tag_name when 'img' if !attr_hash['alt'].nil? return attr_hash['alt'] end when 'applet' if !attr_hash['alt'].nil? return attr_hash['alt'] end end end return '' end end ================================================ FILE: lib/openid/yadis/parsehtml.rb ================================================ require "openid/yadis/htmltokenizer" require 'cgi' module OpenID module Yadis def Yadis.html_yadis_location(html) parser = HTMLTokenizer.new(html) # to keep track of whether or not we are in the head element in_head = false begin while el = parser.getTag('head', '/head', 'meta', 'body', '/body', 'html', 'script') # we are leaving head or have reached body, so we bail return nil if ['/head', 'body', '/body'].member?(el.tag_name) if el.tag_name == 'head' unless el.to_s[-2] == ?/ # tag ends with a /: a short tag in_head = true end end next unless in_head if el.tag_name == 'script' unless el.to_s[-2] == ?/ # tag ends with a /: a short tag parser.getTag('/script') end end return nil if el.tag_name == 'html' if el.tag_name == 'meta' and (equiv = el.attr_hash['http-equiv']) if ['x-xrds-location','x-yadis-location'].member?(equiv.downcase) && el.attr_hash.member?('content') return CGI::unescapeHTML(el.attr_hash['content']) end end end rescue HTMLTokenizerError # just stop parsing if there's an error end end end end ================================================ FILE: lib/openid/yadis/services.rb ================================================ require 'openid/yadis/filters' require 'openid/yadis/discovery' require 'openid/yadis/xrds' module OpenID module Yadis def Yadis.get_service_endpoints(input_url, flt=nil) # Perform the Yadis protocol on the input URL and return an # iterable of resulting endpoint objects. # # @param flt: A filter object or something that is convertable # to a filter object (using mkFilter) that will be used to # generate endpoint objects. This defaults to generating # BasicEndpoint objects. result = Yadis.discover(input_url) begin endpoints = Yadis.apply_filter(result.normalized_uri, result.response_text, flt) rescue XRDSError => err raise DiscoveryFailure.new(err.to_s, nil) end return [result.normalized_uri, endpoints] end def Yadis.apply_filter(normalized_uri, xrd_data, flt=nil) # Generate an iterable of endpoint objects given this input data, # presumably from the result of performing the Yadis protocol. flt = Yadis.make_filter(flt) et = Yadis.parseXRDS(xrd_data) endpoints = [] each_service(et) { |service_element| endpoints += flt.get_service_endpoints(normalized_uri, service_element) } return endpoints end end end ================================================ FILE: lib/openid/yadis/xrds.rb ================================================ require 'rexml/document' require 'rexml/element' require 'rexml/xpath' require 'openid/yadis/xri' module OpenID module Yadis XRD_NS_2_0 = 'xri://$xrd*($v*2.0)' XRDS_NS = 'xri://$xrds' XRDS_NAMESPACES = { 'xrds' => XRDS_NS, 'xrd' => XRD_NS_2_0, } class XRDSError < StandardError; end # Raised when there's an assertion in the XRDS that it does not # have the authority to make. class XRDSFraud < XRDSError end def Yadis::get_canonical_id(iname, xrd_tree) # Return the CanonicalID from this XRDS document. # # @param iname: the XRI being resolved. # @type iname: unicode # # @param xrd_tree: The XRDS output from the resolver. # # @returns: The XRI CanonicalID or None. # @returntype: unicode or None xrd_list = [] REXML::XPath::match(xrd_tree.root, '/xrds:XRDS/xrd:XRD', XRDS_NAMESPACES).each { |el| xrd_list << el } xrd_list.reverse! cid_elements = [] if !xrd_list.empty? xrd_list[0].elements.each { |e| if !e.respond_to?('name') next end if e.name == 'CanonicalID' cid_elements << e end } end cid_element = cid_elements[0] if !cid_element return nil end canonicalID = XRI.make_xri(cid_element.text) childID = canonicalID.downcase xrd_list[1..-1].each { |xrd| parent_sought = childID[0...childID.rindex('!')] parent = XRI.make_xri(xrd.elements["CanonicalID"].text) if parent_sought != parent.downcase raise XRDSFraud.new(sprintf("%s can not come from %s", parent_sought, parent)) end childID = parent_sought } root = XRI.root_authority(iname) if not XRI.provider_is_authoritative(root, childID) raise XRDSFraud.new(sprintf("%s can not come from root %s", childID, root)) end return canonicalID end class XRDSError < StandardError end def Yadis::parseXRDS(text) disable_entity_expansion do if text.nil? raise XRDSError.new("Not an XRDS document.") end begin d = REXML::Document.new(text) rescue RuntimeError raise XRDSError.new("Not an XRDS document. Failed to parse XML.") end if is_xrds?(d) return d else raise XRDSError.new("Not an XRDS document.") end end end def Yadis::disable_entity_expansion _previous_ = REXML::Document::entity_expansion_limit REXML::Document::entity_expansion_limit = 0 yield ensure REXML::Document::entity_expansion_limit = _previous_ end def Yadis::is_xrds?(xrds_tree) xrds_root = xrds_tree.root return (!xrds_root.nil? and xrds_root.name == 'XRDS' and xrds_root.namespace == XRDS_NS) end def Yadis::get_yadis_xrd(xrds_tree) REXML::XPath.each(xrds_tree.root, '/xrds:XRDS/xrd:XRD[last()]', XRDS_NAMESPACES) { |el| return el } raise XRDSError.new("No XRD element found.") end # aka iterServices in Python def Yadis::each_service(xrds_tree, &block) xrd = get_yadis_xrd(xrds_tree) xrd.each_element('Service', &block) end def Yadis::services(xrds_tree) s = [] each_service(xrds_tree) { |service| s << service } return s end def Yadis::expand_service(service_element) es = service_element.elements uris = es.each('URI') { |u| } uris = prio_sort(uris) types = es.each('Type/text()') # REXML::Text objects are not strings. types = types.collect { |t| t.to_s } uris.collect { |uri| [types, uri.text, service_element] } end # Sort a list of elements that have priority attributes. def Yadis::prio_sort(elements) elements.sort { |a,b| a.attribute('priority').to_s.to_i <=> b.attribute('priority').to_s.to_i } end end end ================================================ FILE: lib/openid/yadis/xri.rb ================================================ require 'openid/fetchers' module OpenID module Yadis module XRI # The '(' is for cross-reference authorities, and hopefully has a # matching ')' somewhere. XRI_AUTHORITIES = ["!", "=", "@", "+", "$", "("] def self.identifier_scheme(identifier) if (!identifier.nil? and identifier.length > 0 and (identifier.match('^xri://') or XRI_AUTHORITIES.member?(identifier[0].chr))) return :xri else return :uri end end # Transform an XRI reference to an IRI reference. Note this is # not not idempotent, so do not apply this to an identifier more # than once. XRI Syntax section 2.3.1 def self.to_iri_normal(xri) iri = xri.dup iri.insert(0, 'xri://') if not iri.match('^xri://') return escape_for_iri(iri) end # Note this is not not idempotent, so do not apply this more than # once. XRI Syntax section 2.3.2 def self.escape_for_iri(xri) esc = xri.dup # encode all % esc.gsub!(/%/, '%25') esc.gsub!(/\((.*?)\)/) { |xref_match| xref_match.gsub(/[\/\?\#]/) { |char_match| CGI::escape(char_match) } } return esc end # Transform an XRI reference to a URI reference. Note this is not # not idempotent, so do not apply this to an identifier more than # once. XRI Syntax section 2.3.1 def self.to_uri_normal(xri) return iri_to_uri(to_iri_normal(xri)) end # RFC 3987 section 3.1 def self.iri_to_uri(iri) uri = iri.dup # for char in ucschar or iprivate # convert each char to %HH%HH%HH (as many %HH as octets) return uri end def self.provider_is_authoritative(provider_id, canonical_id) lastbang = canonical_id.rindex('!') return false unless lastbang parent = canonical_id[0...lastbang] return parent == provider_id end def self.root_authority(xri) xri = xri[6..-1] if xri.index('xri://') == 0 authority = xri.split('/', 2)[0] if authority[0].chr == '(' root = authority[0...authority.index(')')+1] elsif XRI_AUTHORITIES.member?(authority[0].chr) root = authority[0].chr else root = authority.split(/[!*]/)[0] end self.make_xri(root) end def self.make_xri(xri) if xri.index('xri://') != 0 xri = 'xri://' + xri end return xri end end end end ================================================ FILE: lib/openid/yadis/xrires.rb ================================================ require "cgi" require "openid/yadis/xri" require "openid/yadis/xrds" require "openid/fetchers" module OpenID module Yadis module XRI class XRIHTTPError < StandardError; end class ProxyResolver DEFAULT_PROXY = 'http://proxy.xri.net/' def initialize(proxy_url=nil) if proxy_url @proxy_url = proxy_url else @proxy_url = DEFAULT_PROXY end @proxy_url += '/' unless @proxy_url.match('/$') end def query_url(xri, service_type=nil) # URI normal form has a leading xri://, but we need to strip # that off again for the QXRI. This is under discussion for # XRI Resolution WD 11. qxri = XRI.to_uri_normal(xri)[6..-1] hxri = @proxy_url + qxri args = {'_xrd_r' => 'application/xrds+xml'} if service_type args['_xrd_t'] = service_type else # don't perform service endpoint selection args['_xrd_r'] += ';sep=false' end return XRI.append_args(hxri, args) end def query(xri) # these can be query args or http headers, needn't be both. # headers = {'Accept' => 'application/xrds+xml;sep=true'} canonicalID = nil url = self.query_url(xri) begin response = OpenID.fetch(url) rescue raise XRIHTTPError, "Could not fetch #{xri}, #{$!}" end raise XRIHTTPError, "Could not fetch #{xri}" if response.nil? xrds = Yadis::parseXRDS(response.body) canonicalID = Yadis::get_canonical_id(xri, xrds) return canonicalID, Yadis::services(xrds) # TODO: # * If we do get hits for multiple service_types, we're almost # certainly going to have duplicated service entries and # broken priority ordering. end end def self.urlencode(args) a = [] args.each do |key, val| a << (CGI::escape(key) + "=" + CGI::escape(val)) end a.join("&") end def self.append_args(url, args) return url if args.length == 0 # rstrip question marks rstripped = url.dup while rstripped[-1].chr == '?' rstripped = rstripped[0...rstripped.length-1] end if rstripped.index('?') sep = '&' else sep = '?' end return url + sep + XRI.urlencode(args) end end end end ================================================ FILE: lib/openid.rb ================================================ # Copyright 2006-2007 JanRain, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you # may not use this file except in compliance with the License. You may # obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. See the License for the specific language governing # permissions and limitations under the License. module OpenID end require 'openid/version' require 'openid/consumer' require 'openid/server' ================================================ FILE: lib/ruby-openid.rb ================================================ require 'openid' ================================================ FILE: ruby-openid.gemspec ================================================ # -*- encoding: utf-8 -*- require File.expand_path('../lib/openid/version', __FILE__) Gem::Specification.new do |s| s.name = 'ruby-openid' s.author = 'JanRain, Inc' s.email = 'openid@janrain.com' s.homepage = 'https://github.com/openid/ruby-openid' s.summary = 'A library for consuming and serving OpenID identities.' s.version = OpenID::VERSION s.licenses = ["Ruby", "Apache Software License 2.0"] # Files files = Dir.glob("{examples,lib,test}/**/*") files << 'NOTICE' << 'CHANGELOG.md' s.files = files.delete_if {|f| f.include?('_darcs') || f.include?('admin')} s.require_paths = ['lib'] s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) } s.test_files = s.files.grep(%r{^(test|spec|features)/}) # RDoc s.extra_rdoc_files = ['README.md', 'INSTALL.md', 'LICENSE', 'UPGRADE.md'] s.rdoc_options << '--main' << 'README.md' s.add_development_dependency 'minitest', '>= 5' end ================================================ FILE: setup.rb ================================================ # # setup.rb # # Copyright (c) 2000-2005 Minero Aoki # # This program is free software. # You can distribute/modify this program under the terms of # the GNU LGPL, Lesser General Public License version 2.1. # unless Enumerable.method_defined?(:map) # Ruby 1.4.6 module Enumerable alias map collect end end unless File.respond_to?(:read) # Ruby 1.6 def File.read(fname) open(fname) {|f| return f.read } end end unless Errno.const_defined?(:ENOTEMPTY) # Windows? module Errno class ENOTEMPTY # We do not raise this exception, implementation is not needed. end end end def File.binread(fname) open(fname, 'rb') {|f| return f.read } end # for corrupted Windows' stat(2) def File.dir?(path) File.directory?((path[-1,1] == '/') ? path : path + '/') end class ConfigTable include Enumerable def initialize(rbconfig) @rbconfig = rbconfig @items = [] @table = {} # options @install_prefix = nil @config_opt = nil @verbose = true @no_harm = false @libsrc_pattern = '*.rb' end attr_accessor :install_prefix attr_accessor :config_opt attr_writer :verbose def verbose? @verbose end attr_writer :no_harm def no_harm? @no_harm end attr_accessor :libsrc_pattern def [](key) lookup(key).resolve(self) end def []=(key, val) lookup(key).set val end def names @items.map {|i| i.name } end def each(&block) @items.each(&block) end def key?(name) @table.key?(name) end def lookup(name) @table[name] or setup_rb_error "no such config item: #{name}" end def add(item) @items.push item @table[item.name] = item end def remove(name) item = lookup(name) @items.delete_if {|i| i.name == name } @table.delete_if {|name, i| i.name == name } item end def load_script(path, inst = nil) if File.file?(path) MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path end end def savefile '.config' end def load_savefile begin File.foreach(savefile()) do |line| k, v = *line.split(/=/, 2) self[k] = v.strip end rescue Errno::ENOENT setup_rb_error $!.message + "\n#{File.basename($0)} config first" end end def save @items.each {|i| i.value } File.open(savefile(), 'w') {|f| @items.each do |i| f.printf "%s=%s\n", i.name, i.value if i.value? and i.value end } end def load_standard_entries standard_entries(@rbconfig).each do |ent| add ent end end def standard_entries(rbconfig) c = rbconfig rubypath = c['bindir'] + '/' + c['ruby_install_name'] major = c['MAJOR'].to_i minor = c['MINOR'].to_i teeny = c['TEENY'].to_i version = "#{major}.#{minor}" # ruby ver. >= 1.4.4? newpath_p = ((major >= 2) or ((major == 1) and ((minor >= 5) or ((minor == 4) and (teeny >= 4))))) if c['rubylibdir'] # V > 1.6.3 libruby = "#{c['prefix']}/lib/ruby" librubyver = c['rubylibdir'] librubyverarch = c['archdir'] siteruby = c['sitedir'] siterubyver = c['sitelibdir'] siterubyverarch = c['sitearchdir'] elsif newpath_p # 1.4.4 <= V <= 1.6.3 libruby = "#{c['prefix']}/lib/ruby" librubyver = "#{c['prefix']}/lib/ruby/#{version}" librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}" siteruby = c['sitedir'] siterubyver = "$siteruby/#{version}" siterubyverarch = "$siterubyver/#{c['arch']}" else # V < 1.4.4 libruby = "#{c['prefix']}/lib/ruby" librubyver = "#{c['prefix']}/lib/ruby/#{version}" librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}" siteruby = "#{c['prefix']}/lib/ruby/#{version}/site_ruby" siterubyver = siteruby siterubyverarch = "$siterubyver/#{c['arch']}" end parameterize = lambda {|path| path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix') } if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg } makeprog = arg.sub(/'/, '').split(/=/, 2)[1] else makeprog = 'make' end [ ExecItem.new('installdirs', 'std/site/home', 'std: install under libruby; site: install under site_ruby; home: install under $HOME')\ {|val, table| case val when 'std' table['rbdir'] = '$librubyver' table['sodir'] = '$librubyverarch' when 'site' table['rbdir'] = '$siterubyver' table['sodir'] = '$siterubyverarch' when 'home' setup_rb_error '$HOME was not set' unless ENV['HOME'] table['prefix'] = ENV['HOME'] table['rbdir'] = '$libdir/ruby' table['sodir'] = '$libdir/ruby' end }, PathItem.new('prefix', 'path', c['prefix'], 'path prefix of target environment'), PathItem.new('bindir', 'path', parameterize.call(c['bindir']), 'the directory for commands'), PathItem.new('libdir', 'path', parameterize.call(c['libdir']), 'the directory for libraries'), PathItem.new('datadir', 'path', parameterize.call(c['datadir']), 'the directory for shared data'), PathItem.new('mandir', 'path', parameterize.call(c['mandir']), 'the directory for man pages'), PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']), 'the directory for system configuration files'), PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']), 'the directory for local state data'), PathItem.new('libruby', 'path', libruby, 'the directory for ruby libraries'), PathItem.new('librubyver', 'path', librubyver, 'the directory for standard ruby libraries'), PathItem.new('librubyverarch', 'path', librubyverarch, 'the directory for standard ruby extensions'), PathItem.new('siteruby', 'path', siteruby, 'the directory for version-independent aux ruby libraries'), PathItem.new('siterubyver', 'path', siterubyver, 'the directory for aux ruby libraries'), PathItem.new('siterubyverarch', 'path', siterubyverarch, 'the directory for aux ruby binaries'), PathItem.new('rbdir', 'path', '$siterubyver', 'the directory for ruby scripts'), PathItem.new('sodir', 'path', '$siterubyverarch', 'the directory for ruby extentions'), PathItem.new('rubypath', 'path', rubypath, 'the path to set to #! line'), ProgramItem.new('rubyprog', 'name', rubypath, 'the ruby program using for installation'), ProgramItem.new('makeprog', 'name', makeprog, 'the make program to compile ruby extentions'), SelectItem.new('shebang', 'all/ruby/never', 'ruby', 'shebang line (#!) editing mode'), BoolItem.new('without-ext', 'yes/no', 'no', 'does not compile/install ruby extentions') ] end private :standard_entries def load_multipackage_entries multipackage_entries().each do |ent| add ent end end def multipackage_entries [ PackageSelectionItem.new('with', 'name,name...', '', 'ALL', 'package names that you want to install'), PackageSelectionItem.new('without', 'name,name...', '', 'NONE', 'package names that you do not want to install') ] end private :multipackage_entries ALIASES = { 'std-ruby' => 'librubyver', 'stdruby' => 'librubyver', 'rubylibdir' => 'librubyver', 'archdir' => 'librubyverarch', 'site-ruby-common' => 'siteruby', # For backward compatibility 'site-ruby' => 'siterubyver', # For backward compatibility 'bin-dir' => 'bindir', 'bin-dir' => 'bindir', 'rb-dir' => 'rbdir', 'so-dir' => 'sodir', 'data-dir' => 'datadir', 'ruby-path' => 'rubypath', 'ruby-prog' => 'rubyprog', 'ruby' => 'rubyprog', 'make-prog' => 'makeprog', 'make' => 'makeprog' } def fixup ALIASES.each do |ali, name| @table[ali] = @table[name] end @items.freeze @table.freeze @options_re = /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/ end def parse_opt(opt) m = @options_re.match(opt) or setup_rb_error "config: unknown option #{opt}" m.to_a[1,2] end def dllext @rbconfig['DLEXT'] end def value_config?(name) lookup(name).value? end class Item def initialize(name, template, default, desc) @name = name.freeze @template = template @value = default @default = default @description = desc end attr_reader :name attr_reader :description attr_accessor :default alias help_default default def help_opt "--#{@name}=#{@template}" end def value? true end def value @value end def resolve(table) @value.gsub(%r<\$([^/]+)>) { table[$1] } end def set(val) @value = check(val) end private def check(val) setup_rb_error "config: --#{name} requires argument" unless val val end end class BoolItem < Item def config_type 'bool' end def help_opt "--#{@name}" end private def check(val) return 'yes' unless val unless /\A(y(es)?|n(o)?|t(rue)?|f(alse))\z/i =~ val setup_rb_error "config: --#{@name} accepts only yes/no for argument" end (/\Ay(es)?|\At(rue)/i =~ value) ? 'yes' : 'no' end end class PathItem < Item def config_type 'path' end private def check(path) setup_rb_error "config: --#{@name} requires argument" unless path path[0,1] == '$' ? path : File.expand_path(path) end end class ProgramItem < Item def config_type 'program' end end class SelectItem < Item def initialize(name, selection, default, desc) super @ok = selection.split('/') end def config_type 'select' end private def check(val) unless @ok.include?(val.strip) setup_rb_error "config: use --#{@name}=#{@template} (#{val})" end val.strip end end class ExecItem < Item def initialize(name, selection, desc, &block) super name, selection, nil, desc @ok = selection.split('/') @action = block end def config_type 'exec' end def value? false end def resolve(table) setup_rb_error "$#{name()} wrongly used as option value" end undef set def evaluate(val, table) v = val.strip.downcase unless @ok.include?(v) setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})" end @action.call v, table end end class PackageSelectionItem < Item def initialize(name, template, default, help_default, desc) super name, template, default, desc @help_default = help_default end attr_reader :help_default def config_type 'package' end private def check(val) unless File.dir?("packages/#{val}") setup_rb_error "config: no such package: #{val}" end val end end class MetaConfigEnvironment def intiailize(config, installer) @config = config @installer = installer end def config_names @config.names end def config?(name) @config.key?(name) end def bool_config?(name) @config.lookup(name).config_type == 'bool' end def path_config?(name) @config.lookup(name).config_type == 'path' end def value_config?(name) @config.lookup(name).config_type != 'exec' end def add_config(item) @config.add item end def add_bool_config(name, default, desc) @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc) end def add_path_config(name, default, desc) @config.add PathItem.new(name, 'path', default, desc) end def set_config_default(name, default) @config.lookup(name).default = default end def remove_config(name) @config.remove(name) end # For only multipackage def packages raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer @installer.packages end # For only multipackage def declare_packages(list) raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer @installer.packages = list end end end # class ConfigTable # This module requires: #verbose?, #no_harm? module FileOperations def mkdir_p(dirname, prefix = nil) dirname = prefix + File.expand_path(dirname) if prefix $stderr.puts "mkdir -p #{dirname}" if verbose? return if no_harm? # Does not check '/', it's too abnormal. dirs = File.expand_path(dirname).split(%r<(?=/)>) if /\A[a-z]:\z/i =~ dirs[0] disk = dirs.shift dirs[0] = disk + dirs[0] end dirs.each_index do |idx| path = dirs[0..idx].join('') Dir.mkdir path unless File.dir?(path) end end def rm_f(path) $stderr.puts "rm -f #{path}" if verbose? return if no_harm? force_remove_file path end def rm_rf(path) $stderr.puts "rm -rf #{path}" if verbose? return if no_harm? remove_tree path end def remove_tree(path) if File.symlink?(path) remove_file path elsif File.dir?(path) remove_tree0 path else force_remove_file path end end def remove_tree0(path) Dir.foreach(path) do |ent| next if ent == '.' next if ent == '..' entpath = "#{path}/#{ent}" if File.symlink?(entpath) remove_file entpath elsif File.dir?(entpath) remove_tree0 entpath else force_remove_file entpath end end begin Dir.rmdir path rescue Errno::ENOTEMPTY # directory may not be empty end end def move_file(src, dest) force_remove_file dest begin File.rename src, dest rescue File.open(dest, 'wb') {|f| f.write File.binread(src) } File.chmod File.stat(src).mode, dest File.unlink src end end def force_remove_file(path) begin remove_file path rescue end end def remove_file(path) File.chmod 0777, path File.unlink path end def install(from, dest, mode, prefix = nil) $stderr.puts "install #{from} #{dest}" if verbose? return if no_harm? realdest = prefix ? prefix + File.expand_path(dest) : dest realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest) str = File.binread(from) if diff?(str, realdest) verbose_off { rm_f realdest if File.exist?(realdest) } File.open(realdest, 'wb') {|f| f.write str } File.chmod mode, realdest File.open("#{objdir_root()}/InstalledFiles", 'a') {|f| if prefix f.puts realdest.sub(prefix, '') else f.puts realdest end } end end def diff?(new_content, path) return true unless File.exist?(path) new_content != File.binread(path) end def command(*args) $stderr.puts args.join(' ') if verbose? system(*args) or raise RuntimeError, "system(#{args.map{|a| a.inspect }.join(' ')}) failed" end def ruby(*args) command config('rubyprog'), *args end def make(task = nil) command(*[config('makeprog'), task].compact) end def extdir?(dir) File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb") end def files_of(dir) Dir.open(dir) {|d| return d.select {|ent| File.file?("#{dir}/#{ent}") } } end DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn ) def directories_of(dir) Dir.open(dir) {|d| return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT } end end # This module requires: #srcdir_root, #objdir_root, #relpath module HookScriptAPI def get_config(key) @config[key] end alias config get_config # obsolete: use metaconfig to change configuration def set_config(key, val) @config[key] = val end # # srcdir/objdir (works only in the package directory) # def curr_srcdir "#{srcdir_root()}/#{relpath()}" end def curr_objdir "#{objdir_root()}/#{relpath()}" end def srcfile(path) "#{curr_srcdir()}/#{path}" end def srcexist?(path) File.exist?(srcfile(path)) end def srcdirectory?(path) File.dir?(srcfile(path)) end def srcfile?(path) File.file?(srcfile(path)) end def srcentries(path = '.') Dir.open("#{curr_srcdir()}/#{path}") {|d| return d.to_a - %w(. ..) } end def srcfiles(path = '.') srcentries(path).select {|fname| File.file?(File.join(curr_srcdir(), path, fname)) } end def srcdirectories(path = '.') srcentries(path).select {|fname| File.dir?(File.join(curr_srcdir(), path, fname)) } end end class ToplevelInstaller Version = '3.4.0' Copyright = 'Copyright (c) 2000-2005 Minero Aoki' TASKS = [ [ 'all', 'do config, setup, then install' ], [ 'config', 'saves your configurations' ], [ 'show', 'shows current configuration' ], [ 'setup', 'compiles ruby extentions and others' ], [ 'install', 'installs files' ], [ 'test', 'run all tests in test/' ], [ 'clean', "does `make clean' for each extention" ], [ 'distclean',"does `make distclean' for each extention" ] ] def ToplevelInstaller.invoke config = ConfigTable.new(load_rbconfig()) config.load_standard_entries config.load_multipackage_entries if multipackage? config.fixup klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller) klass.new(File.dirname($0), config).invoke end def ToplevelInstaller.multipackage? File.dir?(File.dirname($0) + '/packages') end def ToplevelInstaller.load_rbconfig if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg } ARGV.delete(arg) load File.expand_path(arg.split(/=/, 2)[1]) $".push 'rbconfig.rb' else require 'rbconfig' end ::Config::CONFIG end def initialize(ardir_root, config) @ardir = File.expand_path(ardir_root) @config = config # cache @valid_task_re = nil end def config(key) @config[key] end def inspect "#<#{self.class} #{__id__()}>" end def invoke run_metaconfigs case task = parsearg_global() when nil, 'all' parsearg_config init_installers exec_config exec_setup exec_install else case task when 'config', 'test' ; when 'clean', 'distclean' @config.load_savefile if File.exist?(@config.savefile) else @config.load_savefile end __send__ "parsearg_#{task}" init_installers __send__ "exec_#{task}" end end def run_metaconfigs @config.load_script "#{@ardir}/metaconfig" end def init_installers @installer = Installer.new(@config, @ardir, File.expand_path('.')) end # # Hook Script API bases # def srcdir_root @ardir end def objdir_root '.' end def relpath '.' end # # Option Parsing # def parsearg_global while arg = ARGV.shift case arg when /\A\w+\z/ setup_rb_error "invalid task: #{arg}" unless valid_task?(arg) return arg when '-q', '--quiet' @config.verbose = false when '--verbose' @config.verbose = true when '--help' print_usage $stdout exit 0 when '--version' puts "#{File.basename($0)} version #{Version}" exit 0 when '--copyright' puts Copyright exit 0 else setup_rb_error "unknown global option '#{arg}'" end end nil end def valid_task?(t) valid_task_re() =~ t end def valid_task_re @valid_task_re ||= /\A(?:#{TASKS.map {|task,desc| task }.join('|')})\z/ end def parsearg_no_options unless ARGV.empty? setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}" end end alias parsearg_show parsearg_no_options alias parsearg_setup parsearg_no_options alias parsearg_test parsearg_no_options alias parsearg_clean parsearg_no_options alias parsearg_distclean parsearg_no_options def parsearg_config evalopt = [] set = [] @config.config_opt = [] while i = ARGV.shift if /\A--?\z/ =~ i @config.config_opt = ARGV.dup break end name, value = *@config.parse_opt(i) if @config.value_config?(name) @config[name] = value else evalopt.push [name, value] end set.push name end evalopt.each do |name, value| @config.lookup(name).evaluate value, @config end # Check if configuration is valid set.each do |n| @config[n] if @config.value_config?(n) end end def parsearg_install @config.no_harm = false @config.install_prefix = '' while a = ARGV.shift case a when '--no-harm' @config.no_harm = true when /\A--prefix=/ path = a.split(/=/, 2)[1] path = File.expand_path(path) unless path[0,1] == '/' @config.install_prefix = path else setup_rb_error "install: unknown option #{a}" end end end def print_usage(out) out.puts 'Typical Installation Procedure:' out.puts " $ ruby #{File.basename $0} config" out.puts " $ ruby #{File.basename $0} setup" out.puts " # ruby #{File.basename $0} install (may require root privilege)" out.puts out.puts 'Detailed Usage:' out.puts " ruby #{File.basename $0} " out.puts " ruby #{File.basename $0} [] []" fmt = " %-24s %s\n" out.puts out.puts 'Global options:' out.printf fmt, '-q,--quiet', 'suppress message outputs' out.printf fmt, ' --verbose', 'output messages verbosely' out.printf fmt, ' --help', 'print this message' out.printf fmt, ' --version', 'print version and quit' out.printf fmt, ' --copyright', 'print copyright and quit' out.puts out.puts 'Tasks:' TASKS.each do |name, desc| out.printf fmt, name, desc end fmt = " %-24s %s [%s]\n" out.puts out.puts 'Options for CONFIG or ALL:' @config.each do |item| out.printf fmt, item.help_opt, item.description, item.help_default end out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's" out.puts out.puts 'Options for INSTALL:' out.printf fmt, '--no-harm', 'only display what to do if given', 'off' out.printf fmt, '--prefix=path', 'install path prefix', '' out.puts end # # Task Handlers # def exec_config @installer.exec_config @config.save # must be final end def exec_setup @installer.exec_setup end def exec_install @installer.exec_install end def exec_test @installer.exec_test end def exec_show @config.each do |i| printf "%-20s %s\n", i.name, i.value if i.value? end end def exec_clean @installer.exec_clean end def exec_distclean @installer.exec_distclean end end # class ToplevelInstaller class ToplevelInstallerMulti < ToplevelInstaller include FileOperations def initialize(ardir_root, config) super @packages = directories_of("#{@ardir}/packages") raise 'no package exists' if @packages.empty? @root_installer = Installer.new(@config, @ardir, File.expand_path('.')) end def run_metaconfigs @config.load_script "#{@ardir}/metaconfig", self @packages.each do |name| @config.load_script "#{@ardir}/packages/#{name}/metaconfig" end end attr_reader :packages def packages=(list) raise 'package list is empty' if list.empty? list.each do |name| raise "directory packages/#{name} does not exist"\ unless File.dir?("#{@ardir}/packages/#{name}") end @packages = list end def init_installers @installers = {} @packages.each do |pack| @installers[pack] = Installer.new(@config, "#{@ardir}/packages/#{pack}", "packages/#{pack}") end with = extract_selection(config('with')) without = extract_selection(config('without')) @selected = @installers.keys.select {|name| (with.empty? or with.include?(name)) \ and not without.include?(name) } end def extract_selection(list) a = list.split(/,/) a.each do |name| setup_rb_error "no such package: #{name}" unless @installers.key?(name) end a end def print_usage(f) super f.puts 'Inluded packages:' f.puts ' ' + @packages.sort.join(' ') f.puts end # # Task Handlers # def exec_config run_hook 'pre-config' each_selected_installers {|inst| inst.exec_config } run_hook 'post-config' @config.save # must be final end def exec_setup run_hook 'pre-setup' each_selected_installers {|inst| inst.exec_setup } run_hook 'post-setup' end def exec_install run_hook 'pre-install' each_selected_installers {|inst| inst.exec_install } run_hook 'post-install' end def exec_test run_hook 'pre-test' each_selected_installers {|inst| inst.exec_test } run_hook 'post-test' end def exec_clean rm_f @config.savefile run_hook 'pre-clean' each_selected_installers {|inst| inst.exec_clean } run_hook 'post-clean' end def exec_distclean rm_f @config.savefile run_hook 'pre-distclean' each_selected_installers {|inst| inst.exec_distclean } run_hook 'post-distclean' end # # lib # def each_selected_installers Dir.mkdir 'packages' unless File.dir?('packages') @selected.each do |pack| $stderr.puts "Processing the package `#{pack}' ..." if verbose? Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}") Dir.chdir "packages/#{pack}" yield @installers[pack] Dir.chdir '../..' end end def run_hook(id) @root_installer.run_hook id end # module FileOperations requires this def verbose? @config.verbose? end # module FileOperations requires this def no_harm? @config.no_harm? end end # class ToplevelInstallerMulti class Installer FILETYPES = %w( bin lib ext data conf man ) include FileOperations include HookScriptAPI def initialize(config, srcroot, objroot) @config = config @srcdir = File.expand_path(srcroot) @objdir = File.expand_path(objroot) @currdir = '.' end def inspect "#<#{self.class} #{File.basename(@srcdir)}>" end # # Hook Script API base methods # def srcdir_root @srcdir end def objdir_root @objdir end def relpath @currdir end # # Config Access # # module FileOperations requires this def verbose? @config.verbose? end # module FileOperations requires this def no_harm? @config.no_harm? end def verbose_off begin save, @config.verbose = @config.verbose?, false yield ensure @config.verbose = save end end # # TASK config # def exec_config exec_task_traverse 'config' end def config_dir_bin(rel) end def config_dir_lib(rel) end def config_dir_man(rel) end def config_dir_ext(rel) extconf if extdir?(curr_srcdir()) end def extconf ruby "#{curr_srcdir()}/extconf.rb", *@config.config_opt end def config_dir_data(rel) end def config_dir_conf(rel) end # # TASK setup # def exec_setup exec_task_traverse 'setup' end def setup_dir_bin(rel) files_of(curr_srcdir()).each do |fname| adjust_shebang "#{curr_srcdir()}/#{fname}" end end def adjust_shebang(path) return if no_harm? tmpfile = File.basename(path) + '.tmp' begin File.open(path, 'rb') {|r| first = r.gets return unless File.basename(first.sub(/\A\#!/, '').split[0].to_s) == 'ruby' $stderr.puts "adjusting shebang: #{File.basename(path)}" if verbose? File.open(tmpfile, 'wb') {|w| w.print first.sub(/\A\#!\s*\S+/, '#! ' + config('rubypath')) w.write r.read } } move_file tmpfile, File.basename(path) ensure File.unlink tmpfile if File.exist?(tmpfile) end end def setup_dir_lib(rel) end def setup_dir_man(rel) end def setup_dir_ext(rel) make if extdir?(curr_srcdir()) end def setup_dir_data(rel) end def setup_dir_conf(rel) end # # TASK install # def exec_install rm_f 'InstalledFiles' exec_task_traverse 'install' end def install_dir_bin(rel) install_files targetfiles(), "#{config('bindir')}/#{rel}", 0755 end def install_dir_lib(rel) install_files rubyscripts(), "#{config('rbdir')}/#{rel}", 0644 end def install_dir_ext(rel) return unless extdir?(curr_srcdir()) install_files rubyextentions('.'), "#{config('sodir')}/#{File.dirname(rel)}", 0555 end def install_dir_data(rel) install_files targetfiles(), "#{config('datadir')}/#{rel}", 0644 end def install_dir_conf(rel) # FIXME: should not remove current config files # (rename previous file to .old/.org) install_files targetfiles(), "#{config('sysconfdir')}/#{rel}", 0644 end def install_dir_man(rel) install_files targetfiles(), "#{config('mandir')}/#{rel}", 0644 end def install_files(list, dest, mode) mkdir_p dest, @config.install_prefix list.each do |fname| install fname, dest, mode, @config.install_prefix end end def rubyscripts glob_select(@config.libsrc_pattern, targetfiles()) end def rubyextentions(dir) ents = glob_select("*.#{@config.dllext}", targetfiles()) if ents.empty? setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first" end ents end def targetfiles mapdir(existfiles() - hookfiles()) end def mapdir(ents) ents.map {|ent| if File.exist?(ent) then ent # objdir else "#{curr_srcdir()}/#{ent}" # srcdir end } end # picked up many entries from cvs-1.11.1/src/ignore.c JUNK_FILES = %w( core RCSLOG tags TAGS .make.state .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb *~ *.old *.bak *.BAK *.orig *.rej _$* *$ *.org *.in .* ) def existfiles glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.'))) end def hookfiles %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt| %w( config setup install clean ).map {|t| sprintf(fmt, t) } }.flatten end def glob_select(pat, ents) re = globs2re([pat]) ents.select {|ent| re =~ ent } end def glob_reject(pats, ents) re = globs2re(pats) ents.reject {|ent| re =~ ent } end GLOB2REGEX = { '.' => '\.', '$' => '\$', '#' => '\#', '*' => '.*' } def globs2re(pats) /\A(?:#{ pats.map {|pat| pat.gsub(/[\.\$\#\*]/) {|ch| GLOB2REGEX[ch] } }.join('|') })\z/ end # # TASK test # TESTDIR = 'test' def exec_test unless File.directory?('test') $stderr.puts 'no test in this package' if verbose? return end $stderr.puts 'Running tests...' if verbose? Dir.glob './test/**/test_*.rb', &method(:require) end # # TASK clean # def exec_clean exec_task_traverse 'clean' rm_f @config.savefile rm_f 'InstalledFiles' end def clean_dir_bin(rel) end def clean_dir_lib(rel) end def clean_dir_ext(rel) return unless extdir?(curr_srcdir()) make 'clean' if File.file?('Makefile') end def clean_dir_data(rel) end def clean_dir_conf(rel) end # # TASK distclean # def exec_distclean exec_task_traverse 'distclean' rm_f @config.savefile rm_f 'InstalledFiles' end def distclean_dir_bin(rel) end def distclean_dir_lib(rel) end def distclean_dir_ext(rel) return unless extdir?(curr_srcdir()) make 'distclean' if File.file?('Makefile') end def distclean_dir_data(rel) end def distclean_dir_conf(rel) end # # lib # def exec_task_traverse(task) run_hook "pre-#{task}" FILETYPES.each do |type| if config('without-ext') == 'yes' and type == 'ext' $stderr.puts 'skipping ext/* by user option' if verbose? next end traverse task, type, "#{task}_dir_#{type}" end run_hook "post-#{task}" end def traverse(task, rel, mid) dive_into(rel) { run_hook "pre-#{task}" __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '') directories_of(curr_srcdir()).each do |d| traverse task, "#{rel}/#{d}", mid end run_hook "post-#{task}" } end def dive_into(rel) return unless File.dir?("#{@srcdir}/#{rel}") dir = File.basename(rel) Dir.mkdir dir unless File.dir?(dir) prevdir = Dir.pwd Dir.chdir dir $stderr.puts '---> ' + rel if verbose? @currdir = rel yield Dir.chdir prevdir $stderr.puts '<--- ' + rel if verbose? @currdir = File.dirname(rel) end def run_hook(id) path = [ "#{curr_srcdir()}/#{id}", "#{curr_srcdir()}/#{id}.rb" ].detect {|cand| File.file?(cand) } return unless path begin instance_eval File.read(path), path, 1 rescue raise if $DEBUG setup_rb_error "hook #{path} failed:\n" + $!.message end end end # class Installer class SetupError < StandardError; end def setup_rb_error(msg) raise SetupError, msg end if $0 == __FILE__ begin ToplevelInstaller.invoke rescue SetupError raise if $DEBUG $stderr.puts $!.message $stderr.puts "Try 'ruby #{$0} --help' for detailed usage." exit 1 end end ================================================ FILE: test/data/accept.txt ================================================ # Accept: [Accept: header value from RFC2616, # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html] # Available: [whitespace-separated content types] # Expected: [Accept-header like list, containing the available content # types with their q-values] Accept: */* Available: text/plain Expected: text/plain; q=1.0 Accept: */* Available: text/plain, text/html Expected: text/plain; q=1.0, text/html; q=1.0 # The order matters Accept: */* Available: text/html, text/plain Expected: text/html; q=1.0, text/plain; q=1.0 Accept: text/*, */*; q=0.9 Available: text/plain, image/jpeg Expected: text/plain; q=1.0, image/jpeg; q=0.9 Accept: text/*, */*; q=0.9 Available: image/jpeg, text/plain Expected: text/plain; q=1.0, image/jpeg; q=0.9 # wildcard subtypes still reject differing main types Accept: text/* Available: image/jpeg, text/plain Expected: text/plain; q=1.0 Accept: text/html Available: text/html Expected: text/html; q=1.0 Accept: text/html, text/* Available: text/html Expected: text/html; q=1.0 Accept: text/html, text/* Available: text/plain, text/html Expected: text/plain; q=1.0, text/html; q=1.0 Accept: text/html, text/*; q=0.9 Available: text/plain, text/html Expected: text/html; q=1.0, text/plain; q=0.9 # If a more specific type has a higher q-value, then the higher value wins Accept: text/*; q=0.9, text/html Available: text/plain, text/html Expected: text/html; q=1.0, text/plain; q=0.9 Accept: */*, text/*; q=0.9, text/html; q=0.1 Available: text/plain, text/html, image/monkeys Expected: image/monkeys; q=1.0, text/plain; q=0.9, text/html; q=0.1 Accept: text/*, text/html; q=0 Available: text/html Expected: Accept: text/*, text/html; q=0 Available: text/html, text/plain Expected: text/plain; q=1.0 Accept: text/html Available: text/plain Expected: Accept: application/xrds+xml, text/html; q=0.9 Available: application/xrds+xml, text/html Expected: application/xrds+xml; q=1.0, text/html; q=0.9 Accept: application/xrds+xml, */*; q=0.9 Available: application/xrds+xml, text/html Expected: application/xrds+xml; q=1.0, text/html; q=0.9 Accept: application/xrds+xml, application/xhtml+xml; q=0.9, text/html; q=0.8, text/xml; q=0.7 Available: application/xrds+xml, text/html Expected: application/xrds+xml; q=1.0, text/html; q=0.8 # See http://www.rfc-editor.org/rfc/rfc3023.txt, section A.13 Accept: application/xrds Available: application/xrds+xml Expected: Accept: application/xrds+xml Available: application/xrds Expected: Accept: application/xml Available: application/xrds+xml Expected: Available: application/xrds+xml Accept: application/xml Expected: Available: Accept: not_a_content_type Expected: Available: text/html Accept: not_a_content_type, text/html Expected: text/html; q=1.0 ################################################# # The tests below this line are documentation of how this library # works. If the implementation changes, it's acceptable to change the # test to reflect that. These are specified so that we can make sure # that the current implementation actually works the way that we # expect it to given these inputs. Accept: text/html;level=1 Available: text/html Expected: text/html; q=1.0 Accept: text/html; level=1, text/html; level=9; q=0.1 Available: text/html Expected: text/html; q=1.0 Accept: text/html; level=9; q=0.1, text/html; level=1 Available: text/html Expected: text/html; q=1.0 ================================================ FILE: test/data/dh.txt ================================================ 130706940119084053627151828062879423433929180135817317038378606310097533503449582079984816816837125851552273641820339909167103200910805078308128174143174269944095368580519322913514764528012639683546377014716235962867583443566164615728897857285824741767070432119909660645255499710701356135207437699643611094585 139808169914464096465921128085565621767096724855516655439365028496569658038844954238931647642811548254956660405394116677296461848124300258439895306367561416289126854788101396379292925819850897858045772500578222021901631436550118958972312221974009238050517034542286574826081826542722270952769078386418682059418 91966407878983240112417790733941098492087186469785726449910011271065622315680646030230288265496017310433513856308693810812043160919214636748486185212617634222158204354206411031403206076739932806412551605172319515223573351072757800448643935018534945933808900467686115619932664888581913179496050117713298715475 88086484332488517006277516020842172054013692832175783214603951240851750819999098631851571207693874357651112736088114133607400684776234181681933311972926752846692615822043533641407510569745606256772455614745111122033229877596984718963046218854103292937700694160593653595134512369959987897086639788909618660591 94633950701209990078055218830969910271587805983595045023718108184189787131629772007048606080263109446462048743696369276578815611098215686598630889831104860221067872883514840819381234786050098278403321905311637820524177879167250981289318356078312300538871435101338967079907049912435983871847334104247675360099 136836393035803488129856151345450008294260680733328546556640578838845312279198933806383329293483852515700876505956362639881210101974254765087350842271260064592406308509078284840473735904755203614987286456952991025347168970462354352741159076541157478949094536405618626397435745496863324654768971213730622037771 24685127248019769965088146297942173464487677364928435784091685260262292485380918213538979925891771204729738138857126454465630594391449913947358655368215901119137728648638547728497517587701248406019427282237279437409508871300675355166059811431191200555457304463617727969228965042729205402243355816702436970430 103488011917988946858248200111251786178288940265978921633592888293430082248387786443813155999158786903216094876295371112716734481877806417714913656921169196196571699893360825510307056269738593971532017994987406325068886420548597161498019372380511676314312298122272401348856314619382867707981701472607230523868 116791045850880292989786005885944774698035781824784400772676299590038746153860847252706167458966356897309533614849402276819438194497464696186624618374179812548893947178936305721131565012344462048549467883494038577857638815386798694225798517783768606048713198211730870155881426709644960689953998714045816205549 25767875422998856261320430397505398614439586659207416236135894343577952114994718158163212134503751463610021489053571733974769536157057815413209619147486931502025658987681202196476489081257777148377685478756033509708349637895740799542063593586769082830323796978935454479273531157121440998804334199442003857410 75582226959658406842894734694860761896800153014775231713388264961517169436476322183886891849966756849783437334069692683523296295601533803799559985845105706728538458624387103621364117548643541824878550074680443708148686601108223917493525070861593238005735446708555769966855130921562955491250908613793521520082 51100990616369611694975829054222013346248289055987940844427061856603230021472379888102172458517294080775792439385531234808129302064303666640376750139242970123503857186428797403843206765926798353022284672682073397573130625177187185114726049347844460311761033584101482859992951420083621362870301150543916815123 22852401165908224137274273646590366934616265607879280260563022941455466297431255072303172649495519837876946233272420969249841381161312477263365567831938496555136366981954001163034914812189448922853839616662859772087929140818377228980710884492996109434435597500854043325062122184466315338260530734979159890875 35017410720028595029711778101507729481023945551700945988329114663345341120595162378885287946069695772429641825579528116641336456773227542256911497084242947904528367986325800537695079726856460817606404224094336361853766354225558025931211551975334149258299477750615397616908655079967952372222383056221992235704 37364490883518159794654045194678325635036705086417851509136183713863262621334636905291385255662750747808690129471989906644041585863034419130023070856805511017402434123099100618568335168939301014148587149578150068910141065808373976114927339040964292334109797421173369274978107389084873550233108940239410902552 40916262212189137562350357241447034318002130016858244002788189310078477605649010031339865625243230798681216437501833540185827501244378529230150467789369234869122179247196276164931090039290879808162629109742198951942358028123056268054775108592325500609335947248599688175189333996086475013450537086042387719925 42030470670714872936404499074069849778147578537708230270030877866700844337372497704027708080369726758812896818567830863540507961487472657570488625639077418109017434494794778542739932765561706796300920251933107517954265066804108669800167526425723377411855061131982689717887180411017924173629124764378241885274 124652439272864857598747946875599560379786580730218192165733924418687522301721706620565030507816884907589477351553268146177293719586287258662025940181301472851649975563004543250656807255226609296537922304346339513054316391667044301386950180277940536542183725690479451746977789001659540839582630251935163344393 33176766914206542084736303652243484580303865879984981189372762326078776390896986743451688462101732968104375838228070296418541745483112261133079756514082093269959937647525005374035326747696591842313517634077723301677759648869372517403529488493581781546743147639937580084065663597330159470577639629864369972900 67485835091897238609131069363014775606263390149204621594445803179810038685760826651889895397414961195533694176706808504447269558421955735607423135937153901140512527504198912146656610630396284977496295289999655140295415981288181545277299615922576281262872097567020980675200178329219970170480653040350512964539 131497983897702298481056962402569646971797912524360547236788650961059980711719600424210346263081838703940277066368168874781981151411096949736205282734026497995296147418292226818536168555712128736975034272678008697869326747592750850184857659420541708058277866000692785617873742438060271311159568468507825422571 5400380840349873337222394910303409203226429752629134721503171858543984393161548520471799318518954232197106728096866840965784563043721652790856860155702760027304915133166173298206604451826182024471262142046935060360564569939062438160049193241369468208458085699995573492688298015026628427440418009025072261296 83265103005695640943261961853521077357830295830250157593141844209296716788437615940096402365505416686459260302419338241462783388722843946886845478224048360927114533590583464979009731440049610985062455108831881153988321298531365779084012803908832525921630534096740755274371500276660832724874701671184539131864 141285570207910287798371174771658911045525474449663877845558585668334618068814605961306961485855329182957174312715910923324965889174835444049526313968571611940626279733302104955951067959291852710640374412577070764165811275030632465290729619533330733368808295932659463215921521905553936914975786500018720073003 68435028583616495789148116911096163791710022987677894923742899873596891423986951658100606742052014161171185231735413902875605720814417622409817842932759492013585936536452615480700628719795872201528559780249210820284350401473564919576289210869896327937002173624497942136329576506818749730506884927872345019446 134655528287263100540003157571441260698452262106680191153945271167894435782028803135774578949200580551016388918860856991026082917835209212892423567114480975540305860034439015788120390011692862968771136814777768281366591257663821495720134621172848947971117885754539770645621669309650476331439675400544167728223 97765390064836080322590528352647421920257073063706996347334558390461274981996865736612531330863478931481491964338380362350271734683183807511097331539820133036984271653285063355715726806139083282458695728902452215405696318402583540317419929113959816258829534543044153959951908676300847164682178008704099351835 92552521881196975294401505656851872247567784546370503402756239533783651371688190302773864319828182042605239246779598629409815474038541272600580320815319709309111399294952620375093803971373108792300726524826209329889463854451846561437729676142864421966497641824498079067929811613947148353921163336822026640804 145767094672933012300753301037546647564595762930138884463767054235112032706630891961371504668013023047595721138624016493638510710257541241706724342585654715468628355455898091951826598092812212209834746162089753649871544789379424903025374228231365026585872808685759231756517703720396301355299998059523896918448 116669462839999965355861187716880953863237226719689755457884414384663576662696981997535568446560375442532084973721539944428004043491468494548231348032618218312515409944970197902589794303562379864012797605284844016184274353252071642511293089390472576498394410829972525726474727579603392265177009323768966538608 34172517877854802711907683049441723730724885305592620486269966708379625109832852005775048584124451699198484092407720344962116726808090368739361658889584507734617844212547181476646725256303630128954338675520938806905779837227983648887192531356390902975904503218654196581612781227843742951241442641220856414232 126013077261793777773236390821108423367648447987653714614732477073177878509574051196587476846560696305938891953527959347566502332765820074506907037627115954790645652211088723122982633069089920979477728376746424256704724173255656757918995039125823421607024407307091796807227896314403153380323770001854211384322 9979624731056222925878866378063961280844793874828281622845276060532093809300121084179730782833657205171434732875093693074415298975346410131191865198158876447591891117577190438695367929923494177555818480377241891190442070100052523008290671797937772993634966511431668500154258765510857129203107386972819651767 76559085024395996164590986654274454741199399364851956129137304209855150918182685643729981600389513229011956888957763987167398150792454613751473654448162776379362213885827651020309844507723069713820393068520302223477225569348080362344052033711960892643036147232270133731530049660264526964146237693063093765111 18162696663677410793062235946366423954875282212790518677684260521370996677183041664345920941714064628111537529793170736292618705900247450994864220481135611781148410617609559050220262121494712903009168783279356915189941268264177631458029177102542745167475619936272581126346266816618866806564180995726437177435 63244550218824945129624987597134280916829928261688093445040235408899092619821698537312158783367974202557699994650667088974727356690181336666077506063310290098995215324552449858513870629176838494348632073938023916155113126203791709810160925798130199717340478393420816876665127594623142175853115698049952126277 4817943161362708117912118300716778687157593557807116683477307391846133734701449509121209661982298574607233039490570567781316652698287671086985501523197566560479906850423709894582834963398034434055472063156147829131181965140631257939036683622084290629927807369457311894970308590034407761706800045378158588657 61612160237840981966750225147965256022861527286827877531373888434780789812764688703260066154973576040405676432586962624922734102370509771313805122788566405984830112657060375568510809122230960988304085950306616401218206390412815884549481965750553137717475620505076144744211331973240555181377832337912951699135 36363324947629373144612372870171042343590861026293829791335153646774927623889458346817049419803031378037141773848560341251355283891019532059644644509836766167835557471311319194033709837770615526356168418160386395260066262292757953919140150454538786106958252854181965875293629955562111756775391296856504912587 86831561031659073326747216166881733513938228972332631084118628692228329095617884068498116676787029033973607066377816508795286358748076949738854520048303930186595481606562375516134920902325649683618195251332651685732712539073110524182134321873838204219194459231650917098791250048469346563303077080880339797744 26406869969418301728540993821409753036653370247174689204659006239823766914991146853283367848649039747728229875444327879875275718711878211919734397349994000106499628652960403076186651083084423734034070082770589453774926850920776427074440483233447839259180467805375782600203654373428926653730090468535611335253 100139935381469543084506312717977196291289016554846164338908226931204624582010530255955411615528804421371905642197394534614355186795223905217732992497673429554618838376065777445760355552020655667172127543653684405493978325270279321013143828897100500212200358450649158287605846102419527584313353072518101626851 92613116984760565837109105383781193800503303131143575169488835702472221039082994091847595094556327985517286288659598094631489552181233202387028607421487026032402972597880028640156629614572656967808446397456622178472130864873587747608262139844319805074476178618930354824943672367046477408898479503054125369731 30023391082615178562263328892343821010986429338255434046051061316154579824472412477397496718186615690433045030046315908170615910505869972621853946234911296439134838951047107272129711854649412919542407760508235711897489847951451200722151978578883748353566191421685659370090024401368356823252748749449302536931 31485815361342085113278193504381994806529237123359718043079410511224607873725611862217941085749929342777366642477711445011074784469367917758629403998067347054115844421430072631339788256386509261291675080191633908849638316409182455648806133048549359800886124554879661473112614246869101243501787363247762961784 114503770698890543429251666713050844656853278831559195214556474458830029271801818536133531843456707474500106283648085144619097572354066554819887152106174400667929098257361286338795493838820850475790977445807435511982704395422526800272723708548541616513134676140304653112325071112865020365664833601046215694089 76882090884790547431641385530818076533805072109483843307806375918023300052767710853172670987385376253156912268523505310624133905633437815297307463917718596711590885553760690350221265675690787249135345226947453988081566088302642706234126002514517416493192624887800567412565527886687096028028124049522890448168 15056463217273240496622619354104573042767532856243223052125822509781815362480522535564283485059790932505429110157271454207173426525345813426696743168079246510944969446574354255284952839036431873039487144279164893710061580467579842173706653409487110282515691099753380094215805485573768509475850463001549608836 52345178981230648108672997265819959243255047568833938156267924185186047373470984278294897653277996726416846430969793375429223610099546622112048283560483136389901514170116723365811871938630317974150540909650396429631704968748113009366339718498979597226137532343384889080245796447593572468846438769413505393967 32148494517199936472358017244372701214529606506776255341152991328091526865643069587953759877295255050519124541457805199596762210567333445908166076384465183589342153762720515477404466193879418014196727238972417616122646440870364200208488239778452378059236162633837824948613596114768455832408342040970780086 41095268619128788015767564971105114602454449306041732792746397800275041704886345704294273937217484580365505320134717320083763349380629342859670693445658118959823430378844830923452105707338162448974869312012791385772125813291388247857971218575518319578818336960572244046567099555399203328678654466958536663208 92166550199033418923713824997841892577149715275633481076285269142670107687867024550593869464613175882141630640739938334001211714884975032600306279287443909448541179109981755796752132502127330056736913454039526413284519137059580845856736918773597087836203497066909257930043736166431682872083389105176299181629 40049143661018504441607875135884755310012910557581028447435354354754245291878800571089144452035026644953322330676651798951447670184106450649737772686119714700743396359069052813433030118630105307022867200053964644574786137276428546712005171080129190959914708907200288299169344380390093918556722227705114244981 108159089972386282154772900619022507336076619354549601813179459338897131937353741544606392560724999980281424266891537298473163753022749859939445293926707568015958367188089915420630082556748668489756475027008449860889202622698060097015044886961901650857610841562477736791450080980702347705778074391774667412741 69905259478181995876884927656894491893594530150260951315109404530530357998889589977208787140430938039028941393673520799460431992051993157468616168400324834880926190141581037597526917869362292931957289043707855837933490285814769110495657056206391880865972389421774822461752702336812585852278453803972600333734 71821415380277072313878763768684432371552628204186742842154591000123020597011744840460964835414360968627162765288463383113375595799297552681618876474019263288277398833725479226930770694271622605114061622753165584075733358178384410640349907375170170910499615355511313349300918885560131539570707695789106185664 26945345439378873515011714350080059082081595419023056538696949766471272811362104837806324694947413603019863785876836706911406330379274553386254346050697348395574746891556054334903838949157798006141473389066020212044825140294048709654273698482867946522782450500680195477050110145664069582549935651920545151500 80313315938584480048642653013876614091607852535582224914294013785054094052454758327935781971746329853786568549510067442145637007308960551652864942042189241081946607011847245280773379099020221884296226818685556430275385068764313042226925852500883894269809033380734632866477789520106865758504064806906234130588 ================================================ FILE: test/data/example-xrds.xml ================================================ http://example.com/ http://www.openidenabled.com/ ================================================ FILE: test/data/linkparse.txt ================================================ Num Tests: 72 OpenID link parsing test cases Copyright (C) 2005-2008, JanRain, Inc. See COPYING for license information. File format ----------- All text before the first triple-newline (this chunk) should be ignored. This file may be interpreted as Latin-1 or UTF-8. Test cases separated by three line separators (`\n\n\n'). The test cases consist of a headers section followed by a data block. These are separated by a double newline. The headers consist of the header name, followed by a colon, a space, the value, and a newline. There must be one, and only one, `Name' header for a test case. There may be zero or more link headers. The `Link' header consists of whitespace-separated attribute pairs. A link header with an empty string as a value indicates an empty but present link tag. The attribute pairs are `=' separated and not quoted. Optional Links and attributes have a trailing `*'. A compilant implementation may produce this as output or may not. A compliant implementation will not produce any output that is absent from this file. Name: No link tag at all Name: Link element first Name: Link inside HTML, not head Name: Link inside head, not html Name: Link inside html, after head Name: Link inside html, before head Name: Link before html and head Name: Link after html document with head Name: Link inside html inside head, inside another html Name: Link inside html inside head Name: link inside body inside head inside html Name: Link inside head inside head inside html Name: Link inside script inside head inside html Name: Link inside comment inside head inside html Name: Link inside of head after short head Name: Plain vanilla Link: Name: Ignore tags in the namespace Link*: Name: Short link tag Link: Name: Spaces in the HTML tag Link: Name: Spaces in the head tag Link: Name: Spaces in the link tag Link: Name: No whitespace Link: Name: Closed head tag Link: Name: One good, one bad (after close head) Link: Name: One good, one bad (after open body) Link: Name: ill formed (missing close head) Link: Name: Ill formed (no close head, link after ) Link: Name: Ignore random tags inside of html Link: <link> Name: case-folding Link*: <HtMl> <hEaD> <LiNk> Name: unexpected tags Link: <butternut> <html> <summer> <head> <turban> <link> Name: un-closed script tags Link*: <html> <head> <script> <link> Name: un-closed script tags (no whitespace) Link*: <html><head><script><link> Name: un-closed comment Link*: <html> <head> <!-- <link> Name: un-closed CDATA Link*: <html> <head> <![CDATA[ <link> Name: cdata-like Link*: <html> <head> <![ACORN[ <link> ]]> Name: comment close only Link: <html> <head> <link> --> Name: Vanilla, two links Link: Link: <html> <head> <link> <link> Name: extra tag, two links Link: Link: <html> <gold nugget> <head> <link> <link> Name: case-fold, body ends, two links Link: Link*: <html> <head> <link> <LiNk> <body> <link> Name: simple, non-quoted rel Link: rel=openid.server <html><head><link rel=openid.server> Name: short tag has rel Link: rel=openid.server <html><head><link rel=openid.server/> Name: short tag w/space has rel Link: rel=openid.server <html><head><link rel=openid.server /> Name: extra non-attribute, has rel Link: rel=openid.server hubbard*=hubbard <html><head><link hubbard rel=openid.server> Name: non-attr, has rel, short Link: rel=openid.server hubbard*=hubbard <html><head><link hubbard rel=openid.server/> Name: non-attr, has rel, short, space Link: rel=openid.server hubbard*=hubbard <html><head><link hubbard rel=openid.server /> Name: misplaced slash has rel Link: rel=openid.server <html><head><link / rel=openid.server> Name: quoted rel Link: rel=openid.server <html><head><link rel="openid.server"> Name: single-quoted rel Link: rel=openid.server <html><head><link rel='openid.server'> Name: two links w/ rel Link: x=y Link: a=b <html><head><link x=y><link a=b> Name: non-entity Link: x=&y <html><head><link x=&y> Name: quoted non-entity Link: x=&y <html><head><link x="&y"> Name: quoted entity Link: x=& <html><head><link x="&"> Name: entity not processed Link: x= <html><head><link x=""> Name: < Link: x=< <html><head><link x="<"> Name: > Link: x=> <html><head><link x=">"> Name: " Link: x=" <html><head><link x="""> Name: &" Link: x=&" <html><head><link x="&""> Name: mixed entity and non-entity Link: x=&"…> <html><head><link x="&"…>"> Name: mixed entity and non-entity (w/normal chars) Link: x=x&"…>x <html><head><link x="x&"…>x"> Name: broken tags Link*: x=y Link*: x=y< <html><head><link x=y<> Name: missing close pointy Link*: x=y Link*: x=y<link z=y Link*: z=y <html><head><link x=y<link z=y /> Name: missing attribute value Link: x=y y*=y Link: x=y <html><head><link x=y y=><link x=y /> Name: Missing close pointy (no following) Link*: x=y <html><head><link x=y Name: Should be quoted Link*: x=< <html><head><link x="<"> Name: Should be quoted (2) Link*: x=> Link*: x=x <html><head><link x=">"> Name: Repeated attribute Link: x=y <html><head><link x=z x=y> Name: Repeated attribute (2) Link: x=y <html><head><link x=y x=y> Name: Two attributes Link: x=y y=z <html><head><link x=y y=z> Name: Well-formed link rel="openid.server" Link: rel=openid.server href=http://www.myopenid.com/server <html> <head> <link rel="openid.server" href="http://www.myopenid.com/server" /> </head> </html> Name: Well-formed link rel="openid.server" and "openid.delegate" Link: rel=openid.server href=http://www.myopenid.com/server Link: rel=openid.delegate href=http://example.myopenid.com/ <html><head><link rel="openid.server" href="http://www.myopenid.com/server" /> <link rel="openid.delegate" href="http://example.myopenid.com/" /> </head></html> Name: from brian's livejournal page Link: rel=stylesheet href=http://www.livejournal.com/~serotta/res/319998/stylesheet?1130478711 type=text/css Link: rel=openid.server href=http://www.livejournal.com/openid/server.bml <!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"> <head> <link rel="stylesheet" href="http://www.livejournal.com/~serotta/res/319998/stylesheet?1130478711" type="text/css" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="foaf:maker" content="foaf:mbox_sha1sum '12f8abdacb5b1a806711e23249da592c0d316260'" /> <meta name="robots" content="noindex, nofollow, noarchive" /> <meta name="googlebot" content="nosnippet" /> <link rel="openid.server" href="http://www.livejournal.com/openid/server.bml" /> <title>Brian Name: non-ascii (Latin-1 or UTF8) Link: x=® ================================================ FILE: test/data/n2b64 ================================================ AA== 0 AQ== 1 Ag== 2 Aw== 3 BA== 4 BQ== 5 Bg== 6 Bw== 7 CA== 8 CQ== 9 Cg== 10 Cw== 11 DA== 12 DQ== 13 Dg== 14 Dw== 15 EA== 16 EQ== 17 Eg== 18 Ew== 19 FA== 20 FQ== 21 Fg== 22 Fw== 23 GA== 24 GQ== 25 Gg== 26 Gw== 27 HA== 28 HQ== 29 Hg== 30 Hw== 31 IA== 32 IQ== 33 Ig== 34 Iw== 35 JA== 36 JQ== 37 Jg== 38 Jw== 39 KA== 40 KQ== 41 Kg== 42 Kw== 43 LA== 44 LQ== 45 Lg== 46 Lw== 47 MA== 48 MQ== 49 Mg== 50 Mw== 51 NA== 52 NQ== 53 Ng== 54 Nw== 55 OA== 56 OQ== 57 Og== 58 Ow== 59 PA== 60 PQ== 61 Pg== 62 Pw== 63 QA== 64 QQ== 65 Qg== 66 Qw== 67 RA== 68 RQ== 69 Rg== 70 Rw== 71 SA== 72 SQ== 73 Sg== 74 Sw== 75 TA== 76 TQ== 77 Tg== 78 Tw== 79 UA== 80 UQ== 81 Ug== 82 Uw== 83 VA== 84 VQ== 85 Vg== 86 Vw== 87 WA== 88 WQ== 89 Wg== 90 Ww== 91 XA== 92 XQ== 93 Xg== 94 Xw== 95 YA== 96 YQ== 97 Yg== 98 Yw== 99 ZA== 100 ZQ== 101 Zg== 102 Zw== 103 aA== 104 aQ== 105 ag== 106 aw== 107 bA== 108 bQ== 109 bg== 110 bw== 111 cA== 112 cQ== 113 cg== 114 cw== 115 dA== 116 dQ== 117 dg== 118 dw== 119 eA== 120 eQ== 121 eg== 122 ew== 123 fA== 124 fQ== 125 fg== 126 fw== 127 AIA= 128 AIE= 129 AII= 130 AIM= 131 AIQ= 132 AIU= 133 AIY= 134 AIc= 135 AIg= 136 AIk= 137 AIo= 138 AIs= 139 AIw= 140 AI0= 141 AI4= 142 AI8= 143 AJA= 144 AJE= 145 AJI= 146 AJM= 147 AJQ= 148 AJU= 149 AJY= 150 AJc= 151 AJg= 152 AJk= 153 AJo= 154 AJs= 155 AJw= 156 AJ0= 157 AJ4= 158 AJ8= 159 AKA= 160 AKE= 161 AKI= 162 AKM= 163 AKQ= 164 AKU= 165 AKY= 166 AKc= 167 AKg= 168 AKk= 169 AKo= 170 AKs= 171 AKw= 172 AK0= 173 AK4= 174 AK8= 175 ALA= 176 ALE= 177 ALI= 178 ALM= 179 ALQ= 180 ALU= 181 ALY= 182 ALc= 183 ALg= 184 ALk= 185 ALo= 186 ALs= 187 ALw= 188 AL0= 189 AL4= 190 AL8= 191 AMA= 192 AME= 193 AMI= 194 AMM= 195 AMQ= 196 AMU= 197 AMY= 198 AMc= 199 AMg= 200 AMk= 201 AMo= 202 AMs= 203 AMw= 204 AM0= 205 AM4= 206 AM8= 207 ANA= 208 ANE= 209 ANI= 210 ANM= 211 ANQ= 212 ANU= 213 ANY= 214 ANc= 215 ANg= 216 ANk= 217 ANo= 218 ANs= 219 ANw= 220 AN0= 221 AN4= 222 AN8= 223 AOA= 224 AOE= 225 AOI= 226 AOM= 227 AOQ= 228 AOU= 229 AOY= 230 AOc= 231 AOg= 232 AOk= 233 AOo= 234 AOs= 235 AOw= 236 AO0= 237 AO4= 238 AO8= 239 APA= 240 APE= 241 API= 242 APM= 243 APQ= 244 APU= 245 APY= 246 APc= 247 APg= 248 APk= 249 APo= 250 APs= 251 APw= 252 AP0= 253 AP4= 254 AP8= 255 AQA= 256 AQE= 257 AQI= 258 AQM= 259 AQQ= 260 AQU= 261 AQY= 262 AQc= 263 AQg= 264 AQk= 265 AQo= 266 AQs= 267 AQw= 268 AQ0= 269 AQ4= 270 AQ8= 271 ARA= 272 ARE= 273 ARI= 274 ARM= 275 ARQ= 276 ARU= 277 ARY= 278 ARc= 279 ARg= 280 ARk= 281 ARo= 282 ARs= 283 ARw= 284 AR0= 285 AR4= 286 AR8= 287 ASA= 288 ASE= 289 ASI= 290 ASM= 291 ASQ= 292 ASU= 293 ASY= 294 ASc= 295 ASg= 296 ASk= 297 ASo= 298 ASs= 299 ASw= 300 AS0= 301 AS4= 302 AS8= 303 ATA= 304 ATE= 305 ATI= 306 ATM= 307 ATQ= 308 ATU= 309 ATY= 310 ATc= 311 ATg= 312 ATk= 313 ATo= 314 ATs= 315 ATw= 316 AT0= 317 AT4= 318 AT8= 319 AUA= 320 AUE= 321 AUI= 322 AUM= 323 AUQ= 324 AUU= 325 AUY= 326 AUc= 327 AUg= 328 AUk= 329 AUo= 330 AUs= 331 AUw= 332 AU0= 333 AU4= 334 AU8= 335 AVA= 336 AVE= 337 AVI= 338 AVM= 339 AVQ= 340 AVU= 341 AVY= 342 AVc= 343 AVg= 344 AVk= 345 AVo= 346 AVs= 347 AVw= 348 AV0= 349 AV4= 350 AV8= 351 AWA= 352 AWE= 353 AWI= 354 AWM= 355 AWQ= 356 AWU= 357 AWY= 358 AWc= 359 AWg= 360 AWk= 361 AWo= 362 AWs= 363 AWw= 364 AW0= 365 AW4= 366 AW8= 367 AXA= 368 AXE= 369 AXI= 370 AXM= 371 AXQ= 372 AXU= 373 AXY= 374 AXc= 375 AXg= 376 AXk= 377 AXo= 378 AXs= 379 AXw= 380 AX0= 381 AX4= 382 AX8= 383 AYA= 384 AYE= 385 AYI= 386 AYM= 387 AYQ= 388 AYU= 389 AYY= 390 AYc= 391 AYg= 392 AYk= 393 AYo= 394 AYs= 395 AYw= 396 AY0= 397 AY4= 398 AY8= 399 AZA= 400 AZE= 401 AZI= 402 AZM= 403 AZQ= 404 AZU= 405 AZY= 406 AZc= 407 AZg= 408 AZk= 409 AZo= 410 AZs= 411 AZw= 412 AZ0= 413 AZ4= 414 AZ8= 415 AaA= 416 AaE= 417 AaI= 418 AaM= 419 AaQ= 420 AaU= 421 AaY= 422 Aac= 423 Aag= 424 Aak= 425 Aao= 426 Aas= 427 Aaw= 428 Aa0= 429 Aa4= 430 Aa8= 431 AbA= 432 AbE= 433 AbI= 434 AbM= 435 AbQ= 436 AbU= 437 AbY= 438 Abc= 439 Abg= 440 Abk= 441 Abo= 442 Abs= 443 Abw= 444 Ab0= 445 Ab4= 446 Ab8= 447 AcA= 448 AcE= 449 AcI= 450 AcM= 451 AcQ= 452 AcU= 453 AcY= 454 Acc= 455 Acg= 456 Ack= 457 Aco= 458 Acs= 459 Acw= 460 Ac0= 461 Ac4= 462 Ac8= 463 AdA= 464 AdE= 465 AdI= 466 AdM= 467 AdQ= 468 AdU= 469 AdY= 470 Adc= 471 Adg= 472 Adk= 473 Ado= 474 Ads= 475 Adw= 476 Ad0= 477 Ad4= 478 Ad8= 479 AeA= 480 AeE= 481 AeI= 482 AeM= 483 AeQ= 484 AeU= 485 AeY= 486 Aec= 487 Aeg= 488 Aek= 489 Aeo= 490 Aes= 491 Aew= 492 Ae0= 493 Ae4= 494 Ae8= 495 AfA= 496 AfE= 497 AfI= 498 AfM= 499 AfQ= 500 AfU= 501 AfY= 502 Afc= 503 Afg= 504 Afk= 505 Afo= 506 Afs= 507 Afw= 508 Af0= 509 Af4= 510 Af8= 511 AgA= 512 ALDs7paJl5xPh6ORH61iDA6pONpV0rTjGiTkLEW2JsVsRKaRiS4AGn2PTR1UZXP0vXAmRXwdSegQgWPUp3Hm3RofRcDh1SykZBLif7ulau1hVO+rhwRyKc7F8F+7LcMf/v+s73eOXUDbbI2r52wfr7skZy/IELhsC8EK6HzhACI3 124241322153253947064453752054205174382289463089695815605736438952932114700118408072544073767229325045596832952652232288773280299665950768731398747700657715829631597019676014848183966683866396215048196276450953653433516126074463193382764063985175903718735372053536664711482497859539116009770850968340298474039 AOzgU1s6Pd2IkrJlvGND8legXTe50nyDCocI5mwT9rW0YsisY5jaaEOcu51BAq9MmXBPeVX0k/jlXwH4Pn3mCpUAU1rEOsTdcmSJp35siKliDdhTZHHdZNMW+igfXGX5OCsA/BaBcGnE6NnrGWXKyTOoVUGQLEkL2T5yhNUaCT83 166340174936369324883416612727439279977041963320514134445183426741643586944819834936989524033374309932122967866930503619179389342537723598234062828695747850043368572301869699886931403612266216965783079972698791813140295203826980649434652168563255385527187360027803388963151668338040517316899628026707657178935 AO8hrpw+lDiJ13JahLtCb1RenupQcNd0wlTSck9OLL8wB/x6gAoj0PTLV05eZIbz43N3GUSDmmckjlxdHXiBJ9rsoB0P95l1CWIV+4rXblCqxmOdmlm6VZ13bqbI0x7l0cjeMrkmk+yJ067WqUolqQBlUWMTuJVfkxALJYH5xr/C 167923899524385316022824282304301434707626789716026029252173742527362300338760906999615029022863637963070711762128687835779073122264515776657475985362344360699359591353388569856862973447791264902182048648600267737826849280828116753682917256540180401899752566540869918949003470368970029744573140084219550547906 QxAn7yrdVs5tlHV+Glbqdaj67c6Ni8am3bBLOL8PV5HbdrLf2xIPmNugo6MfUwFSnT+ZPJ51+VTOsItaNwCFju0Eh1cqyP3JWyLRPE7emKuo6xRhf+5ik0pTg77LEF4JXW6ofDqirpR4alFi0G2d9yImQPphsYJwYGF/nNT8u0Q= 47093316905427544098193936500644355852669366083115552072584429220248776817916430034648347490325490701471113667554329499736495877969341478442613611948220957798780043076906836236556612316544460763366275536846463456405604189392790111985912854476264292503164100482712281088955640964034295834935468665872932715332 AI9PVzrbJUvmCihwSFans1lBKwudGEZpWWu8pkSK2zVgzGhMvUoGgMp6TG2zsUd1tV8zv7KsVD2t6pXmjT1wPUynufq97GVHI06SGpflDTt30WboYRh3DgYxvso1sOjUXpnDezcaqc2Aiz4nV5MSShkBlyBjA8z2worHDE+uXqw0 100635651531872121827765663065728398779771663753008344681972226973080394359405041113312675686974926993279775427390065833081040771269307007695807025882757371805607979134114890454059957194316765342461291139168706134406917264848659448693866813989352429841300235734400772946895458374870482441457514575059390213172 FiinVicXOqqRLpxcGTorQpSAGeQ/PfDOuzYK9ViFtmPv6D0cYPfhUH4qXEHOejvmX+0b4lfaX8MWPVZxlqpfXiU9BhG76HJxkLF4ysipukeOvhoHzvcxE5bnhSF1i//bOSifATBLBEZInwqSVg5tHHPuuCkwTL91NqhOulp7Lsk= 15560440884463435471963622630292643727112462888414585143143739400703889930416938984547754943252935620248108237258540176511252143752416771350868493435174026287082706690332705481726295797196444796135827460509780634261726494455068460028424141500629527968240913757449787164107068039175831847071025316475940056777 aYrxyQN/hkBne2ayqo2/iDLF3DZGgk080SOMJfsj9h3Z1OfFZM7TJA+y+/O7niqatosvKrfHrAw+Qs7c6tCZ6NPwYJ4QJLOF9bqH2u2a3fkI954voNUctlUagYUJsZXV8hdhLM6NwUyIZ3ZFkPcpTZp7nKQQ84tr1a8VjDIT5/o= 74114640794666001532816944350975062126079079113921109750255283189037502412929005615388097912507598112836936032143435813588205939470002911374442844578739574773399427907766548612582213272643279263782396527705126350063372192910060171635870872236876399794128383338399728947176692692942605589343038282957050865658 AMpCUeKUX/vtRslWiUUuXNl1KA9uDAWjMUkTrdsxxRDESI7iZIn3TR9lW+0kV5fzkLF18iYLAwSGBmX1PS/T0UVFmoBPJ9yS7yktNL0lpQ3noyGFn8HHZ6XB3FkH3jegIfGbvwwhnhhFzpHPrXlpO5iU5Y+rexzp2XHWt4yJGuIL 142031143422642739313498629438991149460874309300342349421794421544918823888598660275343727563280565210534243383322796489809683834300630555650331646026843796764549231159336347965502383849513994449309613369541991287590422095953275586374371960367000083487965487661436037637475372929033613295072397262739084075531 AIMIQVz0JIEKEI+PREu94m3v9XoiU/Q0CpsSuqkwSSje+Wyul5ea9oU5qgtOpdkMUOW91BJo0DW/GMZ8v3C4qyyP29TtjCcAHObJi9hfLSlnTSuzXZnDStooYYKqzfToLToCaAJKCXiXAVW0vWtapLnyqafrf/KgyGZ5u4HfXKY0 92013973253053602863003242446596060337454881568126916916519869242232429836082762281129448384605359749247852792606718908482332975424967542242332487707042773885428473061056052851768940900752317020681189773407893371297668591494665352294885305475871917069040377145530889271334616499701769138948975263435137525300 ANfP+zPBTR27afneyac1KJhOB5Pq3AXB+SoAXJvQI/GkSoNhw5KdfqoIkLcoJi8wClCm424Gm1AdrdGwDFOM/iKTSPkrvMag93+b2EbQGX66/n2X3YRFNkgq/Gtb+2M8oCcAL054Z/iiMD67aU5RWzjqS64ePHsn01bJ7dqLgpMO 151548639867177154896951257541227014781655576169318283047778755573323724856619156348444192550664853912434681577093459933599575436686424046466113215132845213008587152894642577278656978304699131916299275797578171518984206145555369576872231567191579337901913492071976578289189524123204040497290426960375042970382 AK0kHtacLGu1NFWMADq2rG8hpzM4UEYyPOL+aMJbnwXcUYptRIxb0YFZg35RN/RiZs4lQsiq+kEJKzMMV71TsJq59vMkIZhZoB3t8g9ZqBZuq0JYcTICDwRpNSttJidVpJ6P9sR3s1xPMYKdlSwt6EEc9htOXfZU+yHKYgn98X60 121583812047864398969816595368193171848971298823388059338224714026742264861090347096116404814514279627148994345584790617974476594451626305761040465570524035369799925437276511604752129817947910677564301623631349399504187314174538914591944778074509068973226322566160587813128746039859381466427380402262866230964 W3sZlWW1Aev3x/DiH9MzwCAZzBj++x9cknLfGAHwgFqkLH6vimEH/r8hi85hzlCOG5CjwhoZ0D/Hsfr26ZJ3X4chG84byrfDnek1V9mm1++v+clJvlYgcuVgn2Opsba2TILTm1MDB+Ujs9brJ2AAKrE9+ep5nvtQVeG9PUGtdlo= 64240043913835461386212515483198059541440539167395859777194837833769712010594411295323900074066077107346806786205590345517755715510695858065925747020336398305793661773798243627926904542715123849691490667964262778804487343218972081260210371192903128886030021862362141928329650003493687310970684093289133340250 FTQRk9/BIj21gbLwI22fHJWYj+8Ghdcc613hOtJ+/hQmh73HwTXLpaGK9aCptxVbpjW0r/bxaRjmgxu9u1CCZh5yRd7Z46Wk/LIPXGd3ycQzqRMFB7TISFQGJIcFoxRp3Eb5wa2OyrUg7c/D+kb7oFJq9P7mEwIh8TpLzwmu4SU= 14889529068556301710329043521845510156960298822469914567758538023025100741826628180855835334285179977296740667353391766487166458692144569279381035582718738461626140662441222061900764829681913534146898551570916312642104487829660946024590782808750587095559047648957238487820069966851521487428624726655438348581 APYXO6uGvs9qWiEAkcWsaCaCrGJJCP2Z1g++XlJ67oZIgEoWITn3T/R2/c4edAfwUUzNHAYZN1h2dSrRoqlrRXrbxFtGOuRCUrXcGLFFcEbTrtm+z5z8xGRfcorx7Cu3FIBPMK5XcGPcbRZdyP1gBkeDMvuBNAo0/To+LP/dhCNM 172810804474418448604443090732221483571611665465870520701624598983692130272337358406272727413570938793741430131635927237320173996217984860203754686741782921346604605228620148450611724714868551781003004492587584071978757421616871762681049508123223983431502852926521520561941051298696758046005573332373854233420 AIDNxhnDEe1kTJ3XGfTS8zKXeXPRdw5yifm8j8Ibzj/quExy7hFPtKct8hRskPR2qwTlMiW9Ra8Npg2USsqHV0rBoIkX7E3psxq5LBfp/q00l3SEBuLL4K2FGR87bPgU+Duk3RVrNMnColiTcnAR5XkoeWhn/r9MfJMIN9Y0FEh8 90449107125498302548188660544012777357148118984122992664008792590422284061463729084479315745509706793674355738023180454297730948397413371686013210006834869294564190666543874617716180411178090109573192518129248278410216362657350215009192850017507998797754539132540293137589672869131300859207213449571846080636 AIRWavxYRsGlH0Yr0DudwrpYtbrByf9ZsDawKom7ubiRfepqYzcBlwt4adMMnkYSaXeYtOsD4KBm2ZvLKN3++RkYNmxgkyarORBEg7ERyiThBj7Ksw57pNHCAoHtBEhH7Wp9mHhuZtPvPgCEptmwCu9rYhLt4zZp+Zq8a02dkXvM 92930601962515884925250459851491509622611227724602941760145671636277317511265759558869239180653492283311584982044597979173761619470326096725838197524704577188104121460089235709339932110663536557497112887112782062772810759971739760085128369628777812332518137107605855679096146402427144185104230596200130247628 AMNJGLcAiJtL5fUfkesWKYJurdYSnvsOZeZcrg7bemkEVjF6S9CcojimUl+ncr/YY5/EXnU0mg84fObtDxWWdJ7z7l0CFcoALTyEatDYKshT0xvdKY3u+LUShxIAyk8EcGnf+KoEaa4Mx3tg2oTBnVegXClOakNTWw8bu2ItagoQ 137134165107366719462230252606689766470445826753581409513106273517221906418464863733870948759313279128624638614534848890858250894834883265387344539280755177217350585564186248554307335197387734431939154077778003706720017441895613190141376534460438929588407764609772857975000507660651583780079804513519571438096 BmGPZt8XqqI1PuLN4K1/PZMi2rfOYtHEMrcwZdSjKRm5qTkd0Pbb/5zPV07TnM0uLRvIQYTLloEY+GYyn0K5gDTEZpEtQ8ee6Y87zYGDwcf20eqYNxkA7FVV71vqCP/Uw3Oi6B+hMvsWZbvv2vH6MkAeADCrezOtwqVS+irftyc= 4480956865245875120472829476982311611308898564405318773810939350829150182630548948231116574193987272498161864310429976564278532538229396846813874244969927890037756969704618336242255039858182439641759659872128285423988638335967412040624105824571426792562334458751137508116412821914961236269913776304372561703 APqFgCIYbJWuRyEGuOStPvcprj2PILQ0JpgwQ2jLKn3DvkWSd83qh7PWGKozGavsjh803K+ZzI7P2wP+Nc0r0El3q4nzaHvKaCtVRyMwbXv9wYLFZICeM6J1l9ljUMts4tbDoPzkIy3ScU7pYxarBWqMkcBU8qL6NN1vEdkeu0fW 175922170410080716883576123079908758276229469783745771772401183721225804343343063277676406040455068452258961299511343441961963941297631097736305638850193978800615558067791016294285848963023036905095022181004058235239390870177623185946205281141386416867569004073524130001309977475780893497185890756991672600534 APA/rCcGeH6A+6ZwaBBDM6mB6tTD8mjkrOWEo/pK3MCZ+rrErMBnFp2S19GhlLOfuY8BHS+D834Fdm8+3wKYkWnXZpGb+e3v8ofOQ34G1HvzULOYtrEiC4ISZRt2SSyz2hU+PBXjVnplsHWTRxZDmBxTJdgli4ItAqxGCxj/aJ9m 168708388929747822981923386197903561880341990893945097067702518857172133291360611402092714329372304718329568897960770488377524912057166920574319430820488930520807742026377043178502591886293565177404635365772829346030773275726024973460121300339258054215286249329967181244588558220467488638468686270735376228198 AKmwrLP108dCGWOWxE/6woJVLRi/Kra/DvdsPkkrZQmWIlUT7IvwM4gU6bUr4f6wpT08cIQls2cGh7dbSEaO0xLa3mmtKhPiAlzSnz0wuifF3JT9U3uXgUfCZuFtE0z7Oi7WTOrpl3k3GA7JFvXnY0lwblIQALVf6oWyNETnajGl 119160465301384937485959146028591622947513292915838943629387700439301197965652871741710280647524383590817798553034250156068573474278225305190573334054718387045488098320076877626430189054572361967283632592181431701411266656256255758079114072932140551282607247364388070762970060420036793573956057551235306893733 VTe3rCzAL1Sljo3QAXEkAdBy1ZARHZwtrj6ZNRa5ttqd6/l21g4z3iHCeGo4rnE2F8wYTy+NlugjXw86OS+XojW5y6UzTtx0HX5IJ4POqN64aXWmaklGzroBEYWeuFFKcgQN3NOxkuJoDQ6VElP7Epz69kj5CsKJUwL0SjbNrFY= 59841866347633473702601462509811342285929528424012250265905695635971518533504187799047710303717472950129869674786231155102509311322791323986824635569605105662070745033595366004805920086888891275288347907772640070278731650628917037915863439204501060041944275512863990729926528905725569467329169134226609384534 AIZt1xGhC/HrvpPASsvVIVdsu//tn0noyJmVYh3FdQ6yIh1uce47iCsrV1yvYqx5ZTbC0vnfnbjFcWqH+HtLX/DelgvhEwzqJ8hwQrfE1ShLG4ZjAVo1Z4GCjrDcEUMlwKcunuSJssuxeQuXwTLS92+q6QeBSS7OmfxPX29CLb4B 94399298271083745508290936113986978382457275531684761701599029877008571741877683365769553170771833981099580359640421358853566501815723434822307977440496208486103754978934472597505865596938563438311337045817621762649604204720249750058676095769230214181772215323235427976398686727606000594646472236822594174465 NIhTPpWXS82VTA0LTd6TfM+HgLgUcmvnMYtLqPpuqCKZwalAycwl0XFYNyVvaY21J94j92ts/lRYgVtHDhk7/9nLXq5js/lsUnG8rWPHJo11JTxvW+df88aX0pw8u+biOWt87vc1MW1dsMTTsJFJAeBx77qU/Cwto95IVqM7vSE= 36889590210230649939994518345793530042252563793069578097360569338647730438860274349862767107939590441616825589851005429465345268710487649366046960918184701290985280638488938340668212498212581853679035928093386035688597446809895381618260692378376844452061580510108168030682664507293277674052032318576713776417 KXdi4A2Z7tSiiX9YGtDtxUXIfQvPhcc48rUH+Q2SnXL7fLNmr+F4Rf3RiFBRiHKocPfE94pothop5qQJ5X221/DbEKWK6s+ChfQ636jvRxojoLMab3dPtaAPpDJHrfZMxbT4ZaDJT0tpA2e+zZrzBuDs+UUgCpty9nxtdm1gS7A= 29118662951481660380477444121362422614202367719725087486810943918529894738076273660245405874301505615796632229852040910511025841576465052938308369421493312085081188509808322692130449282585522349552501983296872614029139293444558468751646868108213623606366977549477663987815308260383403466635254115908032940976 AIOTBZQR2EJJRmoWdRNFLG4fceoS3KnRTHRpPdllhHODqdg+QxTOcOvqIzBqgdD0JgO12SuNAjLQOiz0jhd02qkXw9Y1adGuKvL97ARFtNEuJiNzFAj7KpDLy2zk2rPJp4Lp7cjQs0fe8BQYnTzTsNRGm+4ybln/gse1YWu9w8y5 92394618277596007469808288231093678404089765494062813665106014405059399079199990128824492247005602685377185496959522609467906358619318009231448503013528692450191782140091818984176967246749464502089280153086163239846744554575017530385347720563798041108608545014076448155956762636929707905789978331102411214009 NzfbJRBF4pqEeborJrjoknJgpfK+DZh2k9cE5dcElMPZ2Zn9im7desWGiBSQnu3KbTO4L/t4+m6nFTNcbIJnqbVSMDHdsfG72rG/t89aOuECQw0HMVVgONNNa6i/mw0jZSWnRLD4fa1YgbUlMd8jeqO9XcBDB4mVtDTxyeGa3vU= 38775530011374537813502898274019389132620116890266344603221997943675706375698597061571989090674289834838060050848545748579361837989319487970580969082824601965845786771062335733318139530316825802589479118956745739691326447349403950997231306042638797277408335778415717988679050762936401945487285814799382535925 Y4BVPZ6necuLSwaqYEPeZp0lt9tTGFl/WCJJbwg7XpyvuwYKtzagC1NLzY5ymBfwGFw1yRlQuyGsYd9mBfC99DuVCIeh0JNrhJN1bNfoSzy5UO5+dmTr+dm66VGSRS0tFcViDTfCIleTV+zxo/xuZT+Bjxq7kZue8zGkjp42Kmo= 69872189501616471647606976308259279995249122669120675885925763529037695584466011511740991152346215507625265226811128801733353566555339153627478941716586678793853828514394269931890370517258825006937741437480128878717892485074131232336852490940507703859793477547154689914725314529986438108117871674332626168426 AKCP9Mto4q/a2xNqM4N7PekbKspwt48OGPre+iqVwPrSP/jWKxg3CvvLNZzN5P+/FiUGIklMMFJ8w76OaHIPqKuwckj1gvCLECJEE+UAZWrNKPmpzd/ootN9/kQhNMuloTFCyhXAUUOXJ7Z0WVLb2u6fn4zroszSMBoWQEKC6lcq 112750701794692134675959811050012620191158543234019977304167102486465198271340022889272244811582365901584420008564301920174477182946432553537794834985703732129975734658113610563794129371053853971031300761815004524681756388784922001759202643614966614186697992611399618828963452661554240362943588548146868410154 APOTAFA2waoAODECaGNgCHa8dNN+cjMnD01M+IeQFytzo9RLMzzzg/gpTUFpyLtFMcfbCkDYQMLXwE4crTimdz5sVvjGQ+5fSFQjoDY6Bw7MO6NAcLzlV/sI/1WyNBKaLQbcl2720n16tdUcdckQNnV+cC2J48CVxYM1c7QQlxA0 171043636512232272455501595416608280460445723238023572475354665686544174728784633443479486247342724860289312593374524429736857970220153680852977711594899595712511352458264354251161579203922747468321999465061463474727943140910084880926005209538535217464825087114791420210981711903880998556269523363208766099508 AMGpxRlB8WVnsGqyyiy3/mzrPymtJW1o1HcDErK11ZwQV5PwTF3c0THwlnxDmcziLWHSWgPQwfRddVDCXMGW9BffJn+XO6aTcWDPmDAh+1DbWJPE1aqApGbHvQ8HONy90dQMZf1ayuwceWCVTuU1wnHdo9F/sIsRbuu7ic2OJDzY 135994898408425255747055209966103741651849229328236418804928584233229830656742052333413774490626915784901255640138520158698845938184666683995579777154437927013722740366497459963753542029774185193376253885864514386760437194444013834088425088260658670140534670789371556026135595577395047002643901630053097946328 AJAw4uDYdSYkOrjtwJVWLv3pi1+UxWge4RmkWKqVquTsAVcT2tRZ+MFdHM457Hl7fmFIyxvGZQy4c2v1AbHEfPR8ID2sCRQpdcfrxEUZPMDqxfnHHm0ziny6W4X6ggdBzMp/sBWaVNTBL0e61/pELBGYNRGFMzGws7HQkr/sro1D 101254336834199527040756567675327011562230719161388328289463594628690618298993695452746353237675715087353241661592074446889034411683413957950360025295995263477031608845241728493807755308798509893719674568267846671753070163272328014412744008880395248474446310603301447848026040555910147467745595720879397834051 AM09TdtXgYL4FI5CGNiVjf0T/AN/pZ5zZsBOi1MAUKMURiXnc1x8VKYTqM9Xb86mqNBBqphynIQG6/3e/YbGJgHlsSdrmKbo+P9daMr02I/7Z76/7Osa8+7Ky6lhVCbU3F0tBH4WvopkCQmuJ267afgvDD5kB+9uNr28deMH00cY 144124056591600568767398029380314564902309327093641173350205276895603332085753288682409279238417493662029954512382520307259348748813767324609446500382301421328754981718014234615523158887865271179104711373675849713359713282937065993613915015084108700238420759344034475478243507306107546245540340758766909867800 AKDhK+/BKGXbrbBh2vM61OP8LN81YwlJKe68KNwUu4tjXlQg7i49Jis7QKPI/YFPUpSNTu5N2iCgeMnCX4+r3NAfivOao9lw4N3nc9bi839SIWdlokhwBHBYmCIgjehUeBAdkU4jKqlE06pIrpRmSvBtn7O4aWTbT+C++ViYAcGF 112973480670453665543892521898882856059335781900313607790238402438320486344365203510769919022496690291280873287383392088872774202832124927485754495093552572232234532821756395965072330282810574669371524103814871172318519695921477775100282448247625395376072233777533359104085023946019406729587713120941266551173 ALxDiSxHjfxvP8ETvpE+SyDPTS7q3o3zCK519WTepygC58KSRfvDnIVIyV3toQKzgqD50kF1Ni5D/wuaSs62y3zg3kELX1g+WuBCc8+x50+kDtbHXa1Me3et/OqVS/QeppkcjK1UZMU29fXze6P/w6aQfvKQkE7koeQtZBKkYc0p 132203344567902304830160099595561253300484092355345272411265169562971473393256361094745618829297250316196312398486598077249124198329075791740755862221465178128527292695331061023291345396067863215552021206609309872689233899464919108147533679134727064586730810633196817136739658243232643507412032417747255282985 VF0YUTvy8Mfi5o6X06DEvLm87r72mAtTdyyLNr0/GXlk0Xj3L2Oi2bVUMtcXQNRXg/mkdGP88pgdaP/eMzqkUU++vJ7t3UgOC1i3SHegpiBhhZh+aZHH/wjFV8Mz2XZB5z8MpMgN+QwALK1TT2Pyt/feQTsOy0imVanB5+OvCeQ= 59242171319056188000481457618922567543461456096441095927600135114274111606802456239311634638536207588762066940095527920532936960549439269891703098017342732142860571277442598349453761561189719823290643146391349978698217357430495238876700400634593256155537598291759795109752990651995982467695091946768443574756 ezpwBt0N6QhTusiPcKrBvSB6yuk/KShTLUFQHdf5J1u1fgDYrp+aOWuXOFVfOd0bweiG4UxBQNXB2IDFWfYON0fBoaDqNk/41YyqXBSkKbiNWLi1y3zPmwTAiwK0PzYp2EPfk/t/j0HsDbvebu0ygcxb2tPqj4EQ1TXEdD007kU= 86533835313999945727720083706940213467453975054116752898416709637030456504024135513972566184073843025739226187558143854850980654667596935003124034699919861200483994576288766702308068265526535622439762454501169018136389983894783905946543636163866717367545972667876983557989192393479830223914708619684891389509 U8BT26zT46tTZnkmTNxGUAlXbJhk5cNi4AMSd8fSvZHm55siMFGJ8Jl7mtdzEFR1UFAyEztf2fUhxdtMLe8ei/OJgM0j7myQ9STucEwnsShT7QS/DjBmfvcC42sl1CRpXkb0ZLrEJCPf+crtLKGrG7ExS1oawIAgALBiMQIL6mE= 58812148564290791415180898639607206220554150794356494356250223429674091688305329629529905854147200457536549527135776329004085047145097927266797668252160196098870200925284256433894773392353678965699083286106628662506590268955650280670838340651598082083455821825076016227525614626726458235627297885815646710369 HfYii3U1SIkBZl09RHaGGA7H3np+qxyNeeCNY07PDl8LwZAaaYk/bHPeBVboan0I2X4o78zCD/gFXFBJ4rxwwUsVjHEioyO2JcpV2/oDOelJBD//78WzBMMSWt7ZKbJV9uYr9ZUM0BUD3fsk1esFCEdnDJdr86U0UMmiig2R+ME= 21039655953870571289679214995029926285040274249531458675115179004718812090027267801012507748013357317597416722235988917212676802092082137617336199787762782958420742299451435320649616271885264333948336627286638368859041172783505464468640994920853000441536629081040963398001710173320125308624362209157720438977 AICOlee3daFyqTrTdtWjVb5M2rclh9BpIo1CRvKo2bF7NYcjrU0/VvbOnTVXDwdeGMLupbi76f0BrfDxYtkzMXvIZlgoTit4g5ennnklDHFBC5cogaGlri8U28w4/h5oMunZ1O4ezdpRgVJe9nTP/sSEMYiNS5IA7Zshdvm/XccF 90275777798511290102824338787811725003177532250296755103300529948194832904403489332420505850668003332750291879153080212231952155092379375422537931240723308384652734942204313672973885652497290433943089371705605128843469306776615573873479312715317072986990219294942040272550822460408702072075001377245051602693 L0QUSVIjxvE201b1ztRZyOOxy8vkUz6626TH4tbLwXjjc+AhmrvplaVlavnOgHqve+/L18XNuAYP4BqdxIcWTx+yxBKm4ZS92dRJdcAtccvZpEJtYjdJvI6qbL5Ph6HluaVZwp4dyFyXuZOJGTfYdTb7PUWM0jNT/xsqyjxSQ2U= 33191267986826803728285073844005357792766429917696698533494382218509532051029343127452480789088572904364699220151221680328978554239767633887572649589456766209242252549993823283929686430100804479376247660556781589549613316880150951333982646510273364068770923588389668733632648346075516618646974067295703417701 APlD9ECKJuACUmQUsbd2GTOpb2PgQVT08C/5hyNEVdA5bWoICX7epmoCKCybdolk+cfEBP6fSz33j+Vn8MbeiHBLdmF6ETbmcyOjldJ902MDvU8dqAa8IgEZN5Uh5x/xzN+3dqk9o0ji7yi291u90rpfIh85PPpDat2B4l5zs9i5 175040148659257809883308984693597046378367187659749953472629929701758633206586720399909808941145946314755491399962797299295431089674294356220216615950668954164397362123668926410543898553191541662075745481299747832013627018846822876386760538344447600390187421938699064459451308870669878673306013635576901916857 KB7N0tE+A5vFhyrd/m6Qe1wTihkjqmBn+rinfmMAzRlvtxIBSyDLzQsOQs7L4oTG64ABU+YwcWVijvoeZNamaxGl4hatAH1pRqmC/r8FMvC4vqiFTbFHzQhkjM7uoHD1aKnxyBVgjMj0E0KZjrRxydZjIR2p13FXjLP3UQSFtII= 28173452509830313810392326357601136401754938805266458365469366750775669869895498658593356375710132149836430968810246171974040975430205200958564616924399794768861923079158311829444850822144940112488994119845741191519421434257276977333662656888696213514226866147767570046232093727585815615828360199830275208322 bxFgV7eXwnbQScl4VzS3RTdcMW+NY6pcGkT1UsqHIeDVyBb8DnH/2/Z+DX3zniR1iW6FPdvhJJeQyPIax1ohILa11R27C1TLxGvTrRBGUycxjEcBIxamHveBsXbECWusYLEakeSDg9x4BTWMz1rTQajkorBoeEjYuW+xBxQtXME= 77994515143740690952370766995249847650881300682406161400195705464876513409097078624084133111941171517535435606295232558665316819077765607639545069239931096306624817379462598756505457054433358548941076472902905065316335603665413114267741896000877284610377452471067725794013283338924419969559537339967562669249 AOH6E2eBzD76QdTJ6QbR/7OeF7AagUif9pEYx7fMqrIsXCJKKpLV/RHIItCDYP2WO4URCaVueoAJe3M/Shj4o6efvH9pf5Q8MLM0rn5MTHWhThivqYQDwjCp1ZsPgq1VFS+gcnmwgHhj2W7XzJxiNPeRXlxI2vL+XTT/wPBYhqEP 158686346608862569574095184731081143351413141116869402750758091813874232272198082464382169470744476593016502816563462778075467588097653320101723165887488327616477297401486647183409348122990505635004320879840358339260797834264972100385692477324858942142372580281421734058008608134075577990829273447077276721423 ANDDgNXOB/rXwmS4KEjiHj7RCDocVrMv5SU0aw6AJzNTBfseFngqidXx2AJKOEeG7RDDN2gzn4K4qJktF0AIPG2JbELlLUu0MFlpOLxamp586qyp67Cl9OuPq3UZTyQhIsSIE3VQkvxuQkGsaV1owDV3BKIWQbQEqMQI3yT4ELHm 146598844784260148346676185962272439320781765598895126402049215152385925250917998794921584290777625240122575975327405909800121511343265147922400813488099624745229653124857224399973509428158163452130086943873214460600035260925149630502192183407327427517292065083168010281295559088633086659209316582810260124134 Vprr6oBnWuxIzyTZjuxlKSdZhBc0upeNBHVIlXpQEnN1Q+XURKzp4/6Vg/koITftr3SMSgGpE7LkrERMGFgYaqM5XZ1RXYFKT9dRJnz9VRDITVZtdkDrU04bqo2Ur+jvZhvg/oHBDTgQ4nPLJfHO3+GEmUtck+g/wOVozMMgufY= 60816213163057201559480662231646403262735082707152897397414589876256824040344252799972529759737904461369360580708093117244392116003622336721789703580184437841209963565058475060017600871779929808204093448248984201640754565635410002090180110910120481044515630478472999135146756643143415057403006410330361346550 do4LGsm0afQLHl9alWF2RVyEKPxLIErsf4pTPgScRE7ZiTSVErbCDeyzd/KHzhBLQs/DhHHcw+OXj541cIRm6jaLVKiT8EwLW/dVG0AkVli83sFh2f56Kk+bCGSKvfGEQcGLY2k7nQ06zoMlYR/xbZCka6Q6kSq4YBDQgigQ1lU= 83252051731120517035090523892596419800592471447735288551342681962005778435125655090199060145942826521644585427683714084736143440310518046334877897672493531918539106001203807757254797471481884534543367685912500572052457610702790097953420236852480969038388056545966568595395722585797418296411673622376893961813 OL2Qoj4xkqRrQmuuLwrABG3BMMBNGjfBtVBNTdBf7g027Ghkk/z3aK3jKT1EPpdiOdn8zXYBSO1mTRGyK3n7Jo8ICOcnlBOF6cZtDsb9bvSVE26MOD2wzl6irU7vzS+s3vGBkN3AazrxPD4czk3xezA9y13DJVnNzgAgIQHEols= 39844525812817530522650122383059885756573694015271773938493414420875846359054562126060762455794481186614035892021706051863945033061233991184379580556219478200155757966121832613842937722944431875100059046588723473670448006803481527981834627086055642349130254917244469014754132003347635357123155857820000494171 Ljgn+3Hcg5DOf6usRumk7P+ZrdTBRmo968HdZU1mS7LwLW3Hii2KNkwMV7J77zA0P1pnvhMSEEeh1RbCUjLtSIbt3RIcOEoc+aO0eINF8r99l83xF57CBI3MDA3AAbtaYATy/NUXSC2h4W5kdsQuR88139MFi5y8E5njqxHu3UI= 32456338403763561215581247445990611953939298888251578685087656354454727113846722731945605696397627662593375001096230320486703167389461057538581895745078593206660798580358701927596287363374862536765135996838944212622199018632046955402325290145163082309469649329852148345837780541107029165352782710901375425858 AMt5/u+ZUNm+Xsucr4RQPUu6ExAOq/Jbcjm/Kb2YIAaEQ1czIL82wsu6YmpHcfMaxLjY+EnaaF+eCWQPeGd1av919+QFbQPeh5DT7ZT9klK7BFyVsN0nEDJQ3AMMJqq6lm4sUeVxDVTmMypYnkzRl7jqzyCRY1MHA+o2LyMECdOg 142886089970163885609957244378225169093559131065687633458877059657380607541767850701139140472705242750285722732461954100519608059127637509286558848391554697942686619832870045594188204522385787253648018847569919409782188708374165437385572046835539379151066214153911415525465041951116179326632238059135825466272 AMvXeHCaa+zk5VdB27KoS8XpjSUngaw7Gwlq6e2RrkEOxBhU2rGWGJ3fhq1HBNRxDf0quqfYTMd1speisaEr3cIyx9BhYwB6A+Nex/Sf9DSixezhcgEz6c5CfwUYP0QTTOiZDqzz+GcjKikjN7DKJTO0WSXMRG8qX8FBbH0rlc9l 143142496664357119491819741364830737485524654099662921673419335301323845847085335210884201567922636945282124120681371777665458057821603161276185071778040317947168899788341482064834489328957963447735297898161379277478278414388733161844053774747425459239004132791029364174047523473372650441001639174571312926565 AMxoMXHfE2i4khsAkv/lPtLQhbWUjP3kxYmlJkpacpicBB6z/TmG5zjmTC/sqzBvBn3J4UvMzKYFyk9/l7Wnuc480500a3S4HRVtMtirPueV8v/SPktL67eN2zoj1VZA/Rex0aRGjW2CzEKGwEn3G2bZSgdT8hKv7AypF69ppjz6 143539479941314279463880342636704987025205547180882175105616955926182352311179043850344463145750154442573797875223178075233807385237935671604701513551125937539235111702655902037518920150424691586943553275517626347557879039695678271564616114192941679606063184290901862703975921261779714258077775731727612132602 ODvOKg7l9RCn5CePG1FfMitkR5l9+7JK67eU+WeA5p1YXCcKS8GbYAKCtXPD2QfxmQcrNYfAc6Yb/kksaq29oW7MzZuTDzK0HXY5xBc/fJzEuvU51gaI0PR3cuU1qRlLqwmIlyt16gto+2E64BgPgIKJcAjx+TfH/EqNeJ77/W4= 39488587053253042573878502921384752550143716864908041972426777545317969264945056510991363961916339225192727727267483337259701961148978214005913510275048195308792987888118270387288989623193626554910652030960235845935461155296845475356011099372367616732243132816329531758943935324760665826550992788664237161838 AKkznyQtB+PGvbVroM5nUIzhJUjiNj7q4fC9sSFbmDgvehnwPElVlie6PimH2FKonGV4GSaxZ+osil+9omfkb4rO3pq8fy5KcFSw/gs09X/U2eEEcUt/4oSbjs2NaMIxQftM2CauULiwfkWdkMFTBkHnh7Bbyocc8dtmrBDdoI8a 118817437232756222334188081193205110010964766506378146125932730686679941224328135190204402802650523704343176483564284220367074983943319572348376466341132480772885833789613392397284313483009178508647973749522358005819092779831781339778163122774381387989185969990310049504391258988402795259963134610905036263194 AJfwWA7XnYbTjlJt+9hO/Q/OubHkUkyMYrN6Jd0cN5MG9Rg8W3i8U6oJxT18p4XozkiOgPlF1lE7hIAW9KRKJKGTue+iw0okLq5UNMu2Ha6l5/wzKi0QzRVTBnQm2zjPlQpgUorBBty5mcbt/B/Y3vOE4I3iVXklVtjQ7zIBHaNK 106695084438708194568048926154027115609888551145480521213711726807296356271397749432698558860759334362315257102647885062353922543502466463770991058956633500180245599467233361812610650830611712448187310827443315947425061886163301613989593906515923245020641415290300558869209909418659128196109640872398602216266 aCXItk5XhuNrbrqJr1Qm04U4y4AzSKDMms11PgVcdf5fCGdizibh6/oZqx5OitM26nRz2vob8F+ZIP0CIyIJU0T1M50dVTbbpwuVNdv/XI6gHekQt0d2g34x1TQJIcsT1VWwGWTPNMtht1hezBAYxwv105AGKnqdLiz04YAdEk0= 73134927546833985031652237686088635686032103401394612286045377544136784429757461671691980910279873140130943470029643791712859175007885735170485461366406852784845528918253441791024065848540598601036357817496637108534035807393364939272891745520961269029038360205258229770737579266643408540634722493263322616397 APNeoaWlyNa554OtHP8F7GAY5V9F7LMoF2ssg5wBmsgGFktrRH1C4FdyD0COrzIb0Vcko1/HiTnA9JXlfGKc3gTHEnO0gxBSDjK41L+EIgUfR0EhAD9iftTaCoBM7qZN3R1MYrSz3sevQZNMFOOnRrzwWEXnJaPKAZXvsqPzOIF9 170899982929163229592439208307232242235219591108657660041403142612622997092685093132858257827585941687488772925553142105567685213341947938835403410054637382864108739466539574004149772568683507025358331323655651148107044968424043673850583150424463706583215452211942132017052425497789362680979074312857823248765 ALhwBfBYpOk1pfJcNut0C2fEAd4hhYU03/ZQBqVe/7MgpEDjro7oMvSdba5kjH/VBssmZVqpvuZ5lG+vI9lXLukhwRKJg7m67HG8lZXvjDmjU/PCjxBPNt5r8/DziETYmMa+fhaMTw4hedZcwDe37t1VPIflvM94sBKu6be9yJAn 129516480651398210587505113546142851617282590236388547627336279692965778911450075230961856270046942312918567973875005814982283590898552829322178788678196583244198944578081007477482775130405341039067711963061287597331433268366003672643052056973656674139309732186091974604170508497340243515339072325943686631463 c9vpoiZvtnj71b8XguD67WayOF57QgOX4V4L++nG2u/RY9VT2+0tJ/C4NIawVa7ScQZAPVLuhV4J50HJX7FZgtY5n+lwMzNo0av7i0IqTS+1BBO8eNJy2wkCbWWBxNybuNnF6OK7eXdPb2Mmwm2OmhN2/j7HAr0cD7rK/Hnif7I= 81358980280155473712258342299472964374474635149963153129588784719499494479288254287754874893180126149146558961101860327826747785201363745989346818037655063262173536227595206355647880155693272153902647256175878517626925488264893732295267833614283963802283320574654949992393798458265266551024756663538388467634 APArEXNLzDydcHrieLDReJryWxFzcsN1dxjpJIVGeJp6itsJOrUtnmXVnETtaZhWsmN3/Zh0R7TgJ253f7PZ/Z2xCEdqF0hs2MmnERSywdWZQ0a0McbDUUaDjBNYFht1wvS6djbI1b8RfayrnEZ0miYdzrrP1ntU+5cM1QBAvj6T 168651870043094856205824264282870999215855903395882323164614939540734011037112413507417141209480771157672307388419164831992909066097194364645695794831939514470650008210390333649278806163193463937050083854756730458780288720541495880958909249273048328511615821480782977316719631334570687241232556472064072892051 RhGyx6xibf0OvY1XjnmX5na3G7emG8PWbvEa1kIjR6pK6K1MrMZnxFefXpHWInFS7ADESNI9LHjZB8VW5QrjRVPMksgdEAlkhY7MyQxaclUlShFl2AfKYBfIIro+vg7mUMzMctD+07BLk+jejRHtPVIxHmNnZrZYds80ve5z3Xw= 49204219353786910100605282012781696579642953908541693903348594981245301165936599174304121350092894937817100350990938057159324959104937469442065996667276651025661016077514839755853073999975805394464570132481314896694678249282338429544941873047382467276103868995474424700207571657816852575364781281563515280764 AKbFfU3GL6NILVyONPVD/X0tffk5HS//7FBp7n6JKMXu3VXvWnfTl32R0WyVHk2yP0iIyi6SUusSicOH9ncO8KJHmaoMGN9Fn+Zq94FTFqZne5NxHmCtwRAbFNDVGg4FeemGXEe1S5Kk1VcvWqnp+QgY0uwa7RtT8C7/T+1pZlwq 117110890075563714812929271250884717870581483065920538069845585667296154465072587148155060755111295509684258790280104272121160614620669593483929827848744548171793187278583947500205314283462739235860439216105116687015890394925743036369717346234391524403038196640934551590543386844279091801685432977718405127210 AJ0xZ9dfRc6P4W31bMHBymgOq+38ETEIMvMtr+wB5WTcsquZY1IUB4IVkrHaOo3W2SIr479IfJOOQhmvyRS4iB05yDI88Z/fJfXarkH53gDivECuo+5+JmV7e0S6gCvOuVamwoQjlK3G32bCV2946ry4EyIsVZ6Alk9xk7X5HfGU 110384671994603894282707302829898242894456931176497230904862171369974466400767175784681299142670706023468915238955836087425993929524341269289746060546848852729416925808186253355106621584826213979718185296723694190658548757311188764342751280681935289121682174507629679900374674992438818324999211250580434317716 fjzmb1D+YBU5Wn1GlwhxjiJS07k+fXxjeNRbOv5SjktzxOXmautO8xZ5ACOlYrTt5G2gzW2PU6sYNfByQ0xoUSyutOuQlD2r+8MnDrxCo6RxT3P0dUSX7q0IVj+oLK4GPbscnKLfe6KqUcYLMgKnDYnc+ztFD+csL6BQnM9WMLk= 88647261832601702291191332432291274285041869480562430895152086741320122435409959711452438332192792226899741738806447713240934608106883094466050154088410020909933636902495700779087737304255058561688767369900548260278700135161077055869478387490726087630962098228537973426295306997128615315548440548541717688505 YDg99aHkQSh9RjytWknbXzcgLD8MrWUEHF46yQLHYANKXaQYyf3yGM9TYPCDUqWbOapqQe+XfOCoACLyRg7vVDsnOPRDI9ZFUgCQBNG06ZOxzktEhnNJoRC99da8jyodFqqk2f9UD1lVa8tsQdatjUDocwgJaDAOpYEyGnUlbXo= 67567767932654827067250684965667741848878457020992905661955722020937161710030993261011062929936964216357930453809610708591260182295097124272956485574313839759737390934220465669626974544253750900911093325004172643146669082793591441922014060981070503803266774197958528843445580649512373693546027107823355522426 ANdsfO+cNtWsbT/QJHGkYAL2WCHWVPrX6oEz78pO8lUwiigVEow5roLI5Tm7GP7XffjF95z5WDxzpoam+Bfp4za75D6ZEHQmuFnpWQAmNLUHdKUE6UcsWN1rbV1uY+x+Nr5Vni/M7PfQi1yRTTJTYav40tFPb9rY48FsUotivoxd 151275723772668372472508916060743043308364940375633847663054782759325087560768667906829087958412643723335046123025802453213225972572697773468957759328009026531148112732519692142632237595562259864125679649273054426879080697360204352423668940795473103047320116317252295126635024518179060076282921965794883439709 D2Z8YA0G/vzEVVQ6itLPUC92r9n9FKRpf6lDPWIgpZOOfIkukPp7zzTlo9Ej5IsBrZBbtGz/eYmlHeZ8Y9pQj8HFW24HeKYqjmR0ujbNxI0QgoE+VUwPVg0HhoQsOGmq47zpXpkDwpOAZbMh/t1Bafq6r2zM0qmiwOacJ8KFUas= 10814483230552506566705634583020057064935800294861277580077052473134972003523900930560478187758928889017740705417070994563709463926267126567504805864719383185267204810142444719634360655595490833208838383875687102074846353850310954150927702228780599083427768247170427544730791038729428517279760042619935478187 XoZpSMHqlOyPYJS7dWSRNDJHCkjbo6+DECzu0FpB9O8bftcxan/06Twbo5d1lEqPlLx3w0XeWtrmCSCaeVcXVtlY3QuPjdKPv8LBnnhslPOVcbGyflaTPXU+ITWE6rwnIF+yWQl3NIwCV4EBtCT+3U//Dt/Ebif9gzfKpKltD6U= 66377743237695515693282032069691369056215169443985727092982918806809030742478033317158686828712146024066618073633406428345129492010236994055590530566431286733776441810601990431112187030942086686719669823512292071202675269428014136307286941704297995292544712278047959299939833088742083527714893795660235870117 QUbbkyJQ0Nru9c/nPbphM6VxHp5DWlai6407KIDbTGvUReVYI7de1gO/BFphL9GA7gDareYoMuej3/SVp8lEujXywtXzjiI+j2TzR3YYiMBAMhsJO1wU9pxy69Cj5xeFFlrOycjE9sPS9nrqnEEEFNPiK/GDDTHj0KuNbWSCLrI= 45838919357034925862751142472777409057791233610959872523563363744902783251621354580995921495295078179996083468819097423327554678806691589090814275138081407920379810144694354354954459732280968086760894209634364189264517251735804373673532012530665557440070501687207620525228416650281363557992436992284712644274 F+uI7ARCeAlnPLO1YR7RJj8LyhtE/EJMcY45lsNMff0YeENe8KOITZVxNA55FcxDYpg9sKi1UV3/ASqkqpH8MOxWpBdT2UwSX3oBkp6ETfJKqiag0C4MS8cQVsfcKF39BJ6KUE7X6KUEj11j2YIIRREmLPyZ0LatG7dN7Rmv2iI= 16797235966984072293396362937533957334369977688369659112225970370748312376722010874726300554329794854683394163379447263409228872034356195791733533528404245739693397078461712458035888813157166614479153484688995068722288153129390850561042173295997770817893349738328312152341860704179681230323810266038959856162 ALkEoXznA7BJlBIfA3Avl9kygQcxexEMApwduVRiXeYG0uEXMQU4rgMJBlPqs+ly8LTIcLFaLnJAG2KFQn2GXz2TNa7w4xkegkrslIJEtBWX/lc7VzRtcLbhaXEs0Ci1ValnW9Up7dYOj3Qw9eNo/9M9b1fD9TI+0QXFtp1ge728 129924120553920201168632484268654219915712271781591182777925696006023100660478316445751842982460082888615429513674356810187315558964251402722465707617058251479494744427428152566665405423424700027316505872162698141109433045594670140335040479559124757490095995568556894332243767736124299898808796118800328801724 Ki3FNTEE870E9GaNtbT418CLSmf++s6Di3hzAy8NgiDOFo+uuicJa54V3JNRxOBc99sl/chfZuaBQt14BFOQ0i+9rm2KD82okNABd+SNfXOb0Ow2taZX8CpkVJYDyphFPyHbPIKmzwMShNx9X2z9w4++tJgzBzGcFTPv1nhAlxc= 29618953883711174042338818332957726953262658484143534778541769862244883781157097499904047532839425875312731531093860721544220959674634750905085721866390609141599426547378130082409488797303960018348798930232014390380383063108812922828160584483043190739354817699497573863286563890071313017508437166939160221463 AJq8tcSnAq6M32ViO4hVGiHY7Tb08cLVyxpl/v0Y5adYblvjrbsFcCmsNDi5PnBOBl5awR7KZdQ1xgq6jIs+SQbccEMvJvGUZW5MgcHrXBj9XVd+8oB0z0eahqXpgYBqLDeHLU6238xR3dJYFf+Xrcrzjg8swx66OmQKkAQVJtdq 108660120968150664552423780971948386965268856900017812123107864829782135741514930439461240950044759098603910762272795612101834680870627850178371693837566833495418727543557712057554231215186486008080050486837716071537742708913279026303380104388546316647349432118287628353129105425052237438199445863950767806314 AI3mfrgcRwtE3mA12gSoQV1xyIGy/YA4pCCvja4mTjvzQOAfiZL0efadxZH5awohCC1SpZDCFsE9yYp4LugHKu/A8zMcp4k5ena8sTPDkSod1yucjybgmVJ5h17Pru28AzHQ/YUmCnojQv55aV2+AUhxzIfojY+NT2PKRqr+vuf+ 99645829268436288676280252226747461064597487404802430565833102291706103139410465131373666856042539909746769688396958963177805479987372681967013633920910376342526433530508868114301205524789149997372160919406352823342811006288909548557622230243808373083272214426118230701324879006645047374853535922112549545982 TmXQ+D8XFKSclXwnTIH8d+sb1IV0gfm7GagJahaFL6A9rvYaZ0NTizkG5DQ0RmXyo0wPmLork/296whsdNdUxVAwnGFlWWvMV0ftR1fOvN9KoT0WtVZ4Rmu6Fuc7q1PskAZzIp7MkOAxILO4iX5dNuVC+GLZYIbpTel3Ga8fXuU= 55052751096768041533898435453266875315629605001878362193939750978427494147944918632414581744895066623527980497732722163665712245580312596487741856071020477624754815927936394948233480228964159047139170955663289543349257377302556035170334384320502468579367401821986660515827461352578142560630318492817238744805 EF6KIBWQiQoHOnBdJs1p+WIcAv9ILt0cnQVo+o/2niOtI0C+eFBSiNgeddhotkQFgHvGUjq8BPYgtLC8A5IFKGzXu4SYj5ziagka0hqfhVs9zVHKNx2NUoMhPDG5R7+giwEGGPOayGHVNbsBf1FBYG91+mwy8hnNbhcHSnvLGk4= 11494909948912248031301686864833544028186348338729984264372557659364976118965740281229664413031002362633393381744365783802034700038490736736266032000546393704814403638058993380993275865674190555703046732456017652317200288968188655019374159412919163798248766655991273308390043613040731449231289437754791500366 AL7wCh8tkFe07qChFAzRkrnNehvda/Teroj65X1Bmcr14+/zeJlZDObYRYBOm8YYSYNgJekcL3o9lLFE34sCMbSJgm4dGwpEVexiLVi+zc8ndnqBDSAnRqtC+3jbInm/v8l6cUvuzrUNtzXIQ/H4FrmPMiVy0EMerkMtkfw5GBsd 134080980697158076909534078193319899756347955848461100874771253577754225619652121295523443912922220564492468474647193062555347746840044705102003079330399499915801536721237211615317000955332058281901995149084303143543150689010335818219129745452688372571010816270728441637278434982752674030696337642893239393053 APunLhlblRi3bbRBwSV8dsw8h5SvT8ncAmXPnca+e1dLzrQZzL7P2OhFope0mW1MCDl2kJPiGTdK3SiYJVsAFeR3r/0z96g3oq+8uS66T6VaJym0QToMsqQF4/fUMaTo9HsukyPyOgjVIU+6TiFd3SxQKIu1/GpQWVQIP2pkHFKM 176716779397275986910036615967409090183531310366246043951791503601618945774743601662530806467045971394247287367421508126613573039423674729894091424105133906122821596079925540513892022311039293333114333317886304014722168786051080135090242879622144693440448171583324154550086458411590240882982297314605229953676 MM6B5AgdJKe5OLlPzcXwi9WhqQjx5KsnBYxxa3kWdGNTdk/IN6TVd4Ptn8lWkLm78mw3DXP4Ol1sQbIfkHRoKFUN6TaWg5aDCJBDXyHSTZI2FDc1di0Te1SwziYn0sIOe+R+rfuLuHlcT1xaZBgL6+dDLAZaZza36UEjn5i/pTs= 34273208848307582992498656582721015257885595139328466874135636009184357438445251703533153492315835793684794951576799764181908090765379592683793969576893243386892292517067596035059342970830813419330530731370385186653239446376170533147020072285887964430731437765184844167400169982662183791828762458682426369339 AJK1dx77ZA4F0sYCgRL1LKSTvjGTKBHd4QBeVnE6FKJxIow82puqtsVZ7TBxbECex+LkLQPrEbuQaVr3giUDjg0aJCE0D9ZVXCUS06qulqcCCdWgGFHXDOQzTWDn6TlJCGxtTEMbMxSlUq1q0iKZ19kwMHiT3GydBn8/G7tIYd23 103022457217861194294329435482792508957642944252832971366936865663608381648431732294396977429863681671686490913575377744795372643599438468695483808375208871881849232129651519218503507811863794426234594709451104684234156597418383183271923307418704786548452806494411689822939919114966188329657999811363991575991 fPZNsqUYBbVGA2FAiglnByxGJOZkVSpj8Y4QNW5wq6o/1e/PRwp0TLYJXIoCJRs82pAj0QDpQbHl5lCZmNxEIQP8o8xI//HCPxPIdgBJmSfm3VGetrOpqEGU0KJJqK4IsjoVpAfPFMUMOpGNz9CSvCHGk1AKrtYvrTJEKmETuig= 87751387019308584846595931543798879607048239290774788042055795835726250309378365187899578817976976035304304847968410200168743967600896348021636654074952051821111673620467434295067182213181329543946368332581250062140819766061014427755090798550122401239987766844126425179573454145697756278292448630509686471208 EmT6DUd0bxcdprYhAnycQaxm89kltJOlIOGFFRmEK90H3RhzBGr5PRVTJVqemFVpVliO1gy1nPHgqDGVNIE1GXhrhyFJU6m+HJeNcduippRe38xPCiuraRkXao79X7WAiVYUq6RIH+UIRnfTvHBgzTwjrOvKJ5853hYmGaanjh0= 12917015385266582065020051081997430892582163827812227349569911846746592973268746845211126663077128575098045461893559476227689488349263954564361736197688317585888118974603264677576027836032271531903881104937422976121352854003385726888601980526287956222142458858211589791399646989299770657341412683499692330525 APtOYyWzdY1A/YU0SGrtjPdMZA5E50Y3hJVXppwuuSk04TjXzcbu2Sqp7sMnKYbToRW4nB5p2UnaLPhTRy0yszOd1auLngW+0ttCybD6nTcVoP65gYOwXGfSEQysqKLb1OfV8kYq5Ba92Efn+CcWWWuS0wEr97W5M/Hccx9bGu0r 176473215292413922394356058789571494026727424839036665031567966488209592078148711908841964690807374236235612412767651029865069639786447019874344449598703213025389428836803984245755885691094364960118900160737925054803955567361126391353868279642836569627177281508980029006921064654964339077608785831304875404587 Vs6bjpYfFA1R/QTeCfhMuZLZ+Zxo6wxq1jFZpi5SBR1LaUwAtOAj38OJC8L7zmxSOj/RGEmJHkulI3E1MH7P7xlWbY468/azfot5fX9BgHrtptV6Q0dkBUg7H91+tcxdbm4/V0HGQGa2rZp+XK1rO+U/d0ki6iNbsCsCR+OeyvI= 60957991334776853645581868230398759578123373154273044785333939425321390401088800849629483265841435899835570419798325123273632247193463641611211088549152950252041797959644227170492417662363676228611376046334386877555777556575818860902071813120592757466883038430756577949025778080997296219236534786815367760626 GiauT9A+wmwJsFbS2OPIM6ultIbU+kT2NgACn1jFAy+vNBahdfHMCH0jJdCs5TbmKTCeiEf3ITc5TV1OSvIejJ0GRkTf80nY47TAhiP1aehZvMAv59NQHHTDUE1U4TPVYKIyFpm1V1A+JBHKJzuGrB4lvqB2ed7k4m/ZD5lFLMM= 18363925023885496669420377869542744504974590667921570026763131637088916425434675950812384919000566852243714758512996458727914094904422651029609645299422563453163291342992902510788457007623888307499601267675322986672697397389663297565071582648674012080122614260400848960757021864980761735684874056409664531651 AL/9KOZLtZu4+ZQYQsmOgbST8F4RV4N/Z+l8qsbCFlHdXHqTTkcN0chsccE/3KkVTZsAnAyJqogbAvB/RZqttaK5a8iKlOEoerUS92FVQw/42WhsVaFggR9cHVuvCD6QqclZjSBQKQzUMy0YWPWlycAZDIv96tooA+V+Fk0jbcFs 134819194171226950171930028888667967094069342154233489571728632904658607624703819928943642011918061760802468868660586005724399808048609316802502143143910585363214684061242274402109137825176291816945489430125510625857564490981683683589784133305376252294774711594646923226452625156299996630452243345104727556460 AK5x2N/4+PKlsW/fNrw76CnE+nS76Rd7Ugo3IKhMTB/IuCc5xG4MQHo5MlWE0oVkZ+Gs4CxUpvD/WCCjHHFlSxKG4mC6ehz3NVLglBt+f1RWfPkF28JPd0UaIOG3um8kG4J3JDN48PXOPP86A0H8ZYbE5+ImmXsGAcwvScUQRInU 122499245103202714319465533564374494931278163571999934877854825659720649344163774228004853964635693562785966889622928722984134944784141208867445419597834322541679973956606275877526560988151196822256754309120410807075405427166696093800381410682490767468563176131997424692783482903880902119461752084196789357012 ALZ12i0hqFhwRAikcoahYzH/BUolhgZ9Jz6adLvvTO4wk6LLOpNC/zCz+LjM7HazZomT1SqeYJ2X+WeGFLADHuWo+Gp/I3S0UEneYHKJxoU7OoOtE0mB0BCncLckHao/LmbpnQpS+Lx5bRsr0yE6oWNea6gbyRm/R0to74MI3/KK 128128022342420083856194424802390993133863171077961467523372211039771843125192435716337829530528063182315478279257832480290950255315151577221042903861075751839976362752440630888566422581799720709574650482021111126414843635330535518992034746102956214991673417580508389225948159518319625680855827280146399752842 APXxvLifWgehdwdTRAJP5KrchRzgbUsyMWKcPGm2ZkwGDJjoTl2LIOOGVFiL4CyPBxahkEHf0nMxBN5oNGX/Y4W4PuOAC8gMgHzdLkPWkpnTcyoe5DD+fQsqNuKVw9nvyB15fx8k0d6b056nfFjnnRqgybby7MSllAWSKRYRdxVm 172707950911363219032118650562553641123743396229371815589867086054370029540557395298194067635069298952836929253340374819975848769009260895874615676938511747311585257140973518651959463416682165208985512233703837931718385346209362040743041262031997793519095342415901373534535662377972036003546589624834285049190 O+9ohtZ9SzGLJoZM8IRQAjhc/GPt2X5G+M22ZidYjx9WgOTrZDXorSyxLuHxay6djsJSgjxYMj8MuanYSn/DzPWBB1Gn4cDmIsfeYuzO+vUJ4l6d0nIvBg9Iqs61/PGFd46YxhnDiVQ9HEznyTjzESnNqc0+/OkQVJcwNHAcZBg= 42087920806448980363073662127262313840530298932643042322138035915324224188032438119079107631420338701086802583985117830416851550991102672642532160807467909040086448764318690465254898516502941122327185894900817634110254371864896139724173087625913998657136384357741816102965779105122269429701537815263708996632 VJOZmvqrqsIUTQSSJpZPhbQIYN2tsfBhAciWnfAYpwjK9/ts7OP4Qgdp6T/V2EsSRPnfZ0VKdLg1CnEWDhfcODo+/BZcUrJ0AviFAEtdeUhoMSWXtjel9Ln2guHY4s33z2cN70+e8gfjes65lCzrxUIXEF4nKxzKBnScoooQP5k= 59391682001673484862915842850714742391303140646889359425353339320546979084250010101273851580028171449840778038774656177449549941659895629203970455580974953864068394275066532699748911169800076515776388213090834432354601344176559839798153004796057709798368011673585434643656820656931921831615507416411999846297 FRyJCOgPziO6RDHX1JgYGZRcSAuoQFIZM4niD/B0twK3l+TRpmVigKZAJnZZFtmX+0JQkDwQn3lcBGQIL6mgy+j0hD58U2/Wd6xebuHSzf4OHVGo1cYoqZLplszA+hVCoDVTHi2YAZ+GtfQEggumcNVxqfEZd6D9Nu//hm0t21M= 14824975573460749317081504809641216868382341402512168178334301409725840669112911061147252565570697788806398498723577368905065980113760265945344671897779830912242224090954834750057278285419880820811348943398148063418809729356397202526234113316098584002071850758705282845646489058224513019380757604894853946195 dUk5LyS7mduFJlvh5o8R73kJIeeTh0Zli/y3XjtIXfCaNRf+wDlD/pX91JEwsQ5Mvj8yq/Uq13QyWhoNwsPpXVcJtJ+02wtIn5darsBDfzcD/LbWhl7zTRUeMjZ72gAWi1djx94SWjrZJS2oWZU92Og1yOyKRG+ua0AhHfYYh6g= 82361050315899968537319599868832189063658136463903643442673674137187842597528653416212822014359684261704550279153006971937114135373937934986951573613797195556144113400128502946618028800530164890707031379614952207482505803377774320259789692177752930767589642007257364960987343146063216186985472686575891023784 AI6rejwEznR35rIPuIz0CP2aWyhRUR3unJ90YfxyuVYxrqOJQGSDTSf6SGDDw5MqpZXa9pWuwpyrb6smOq4ZtC3Er7lipJfXDjhy+0k1qcfMjmqbATUscwXGpgW+MO71cttccEz6vhbjndi8gvG5M/vfL2l1jA8nXuBd4e254dbz 100186164434910864539376019601151338080943067893748898987236087770762310617199833479771711726248130012472861788210345311298499515751355424063761182369333224929721733015910055321263016834247318907562652286587380604998130368845939290804442878127169587599285040969551065995197981341260363722618429042861484922611 AJ5vLZX0fSs8dUSBqd5hki48T9cYuR0atxR+qv7cRu9nD1vP8uNVR8dLitg3XH0RARt3ZmOgi/AuggZt6tTxuIBg+9JhBY9WW+BLL5CnYWHC3AKMi7MQBWciLtmBpyF152bDaEcV1PXxtml2KxX0Ba0C+hGVDmJSdi8Kjd4AkfU6 111256341508463539324514225759801553679558662737345522765042612717818066374840372549356543720386819501973783940451033901079765311790026584654529398345993992144903839534037331533660672892487693477412528974248713261092693018326068480417183236210881306241164169849090833681510163753605662526243408192127670285626 ZhXtSzn1GiFfHHnSKUYZiTcEWqlI8owyCKFjCQ+VEvkdk50m8uN7RCQ6ZhI545tN7Uy0WdLstJhgJETBYLHHIoWsJn07mgPxuyO0XsqNroICMQEOO/YWQFk1c0VqZifcohQAwJj7fONzM7hTcA22/7gVigJ3iLq178jZOJsEPQs= 71686982768953132894579286530164112027530221141251507987469672039995314435159469907420372652392376452531392493658576814100773556880394271726970628960571077839124343525055625420896355363707908511865700866168843075071778015504724409171911254647909938237551680861008772396291072284353858575645679153885560978699 Vc8Cw5m5yI+bJ5sUJYm/F2wyZ5x3D4ydyL0uU/3eVF2ZJu55OOlC9pUyyv7WGExClHvWpR9mhMnsqCLyseLfM2Q/YXJ7cjGPKp2xd+fvwHa4hRi1FdOxs96rJnb+HUt9hTwQByXgzpnUfs7AqrqaNf4WSlBNMu0IOOqDdB4iVHU= 60256873326783629723455608618518793848697944184579877638436234491615392142659293975260290798403892159720925893207048153291000664050780029732557737984085196691225472664027706406879051455184548871511448456651238810812870905640934953489289909009741493031472382758586341375517766302753448531830002512912250459253 QmeUn6cbpE8YrDfMETz/+KVFaK+d4NHHzcdj/MnjcmqQSLpP/XwCW/aeudlN3SfKd6rNo1XZefunZO/ek+PHEIy899WzjiJaajhf2X05fl9WuPEaMES3Yrr+ClogFNQ+9jL8+7L+J8lDuqQzvchT0U0RPay5HSNZw+ZouVCiQ18= 46630904037845609335515965570673490721137364238213103678233212262384415738654627185220187275286458759154841820256007930773120637898228224906635911124921895934056288121005350040349882413280772888907627838315559544636626856478316691755270725623680935763476199888127096014398699432042227882284223578563208692575 ALUBYIShA4w5kRUa6iNF8S33DqaprdOWjVBnO+j9CCGtUh+NNwfpKR8AKf536MtuFFtwaQvRIlkLpaTYXuRxzyU/YG2+UfRQF3pEmXQhcMxJqFzqZ5nWCIWlJ/KtYS4lcC/B7hD2UGAktnIdjVUTSxX60VzA+zxeunV2iBZXQlEs 127106299687401374061881872616647348819431126560557369258073443762502337592227172639640997680536372567116568811258505773087926491911004324918919511363985868314578663758269650473780772688462266790559846182685481907703974916356209771821075179827563487466641669110315430790405454641953880582274165368514679034156 ANyAdMnVCVjmUZGiVdyvGE5mUQpKoJOJINqMAfzVUGvvxXFmGdoAx+xsDRNAP4KoijpXk6E3yPBPBZEWyhiHnyjEkktK/gX6gnb745afS0QIlsjhKCk/W/BHXkzC862Llnc1ZGAIsERnGceEoZHdICfDUh/7nMFp5WuSMzPB7nEO 154841617115465511611746667401422322067517612306328612547616471923266281876818466022676728696273611923942543658633762267658490816264271663863494188027433799849037906883352478212451733963905925106470599843045599411842850386623187980045961158399934160107237440980574028985561404965317132715808604373199725949198 AJ4nfhDe+HojR2YrprDHW9FVUxsZvoIekwlNL2iKFRFcTB9IcEdh6QnGcaRinev7yEYUsL6saSxUj39uWlqo8udJFdszuuQUmnloIi34L5uj0m1OpLy2dawpFQr8pqyA7go4ugMMj6XCtiVnISUcK8wjHgY3Jed/EKK8k5ce0Jxt 111059703393618496515021583605572584329116596402705082562306930876194742195701060137568030171429700588269665205795898835699633817098262654446852249498668467827435829513531633390969638488553144849154126899372953755511962841193763362947708260103832329116485114451074371844037650417731807385491783373627950406765 AL+heSTflb2MkRYFTKghfzqlVQ1oE5vcx0eCIsy9NJ2NGFXCRRvoGDVoB8UEsUWIRnaA+MIpwDKGpbOS8kRQrvBvPe/xM/t3jrGkaS6pN064+bCBx8Y/Jq31ZXNG8oUol+y1Eo6fkUKNl4EOetmZWK8VmhVwol5YngDffj4Q8ned 134567692290185631768518572983694048149859804864902017394351513816079806629664302312927579302025923096596995134868068794900003728293470554490807959649153000914807604036531509869958441069678002226922395630284261949256022972967357884468325217602330254290548618134453007903724438628204981673400911693835033278365 AI272d2sbYIi637kHZC+6lievgcDvT5VKaCnus3fHwm2vfao7oYu31P4st9DlqPWJ635X6QtLkU5HgvVSy66MDj2fcOfwVL09ffkZYnoGNdhMADVgOq62Ro5cCpOdw8Ko0cCyVpVIaSysPuqY7kiClf9GTdyZz/uYHDgwWeNrc4R 99528854246023003959943182132914587584844397870416002887630245681136432049666385367430032197518895755482367603560037194955739661569172773017279832774100155646116233705958563163070414171045438199561777058338188494271322834524386565519620661180246416329082614115142485663975718653564590519408413408765689056785 AN9S8vPzo4SkyKsk07nfyD0um1riJzRqqWF9KCL+kWMHajurgPACikYzu61tL7l1mNEaIU16Ndz541o+y76DgsTLYszu4KXUOEt1Gu3eHy05Fq18zCDlNesSVjkZjPmuJr2ku+p0cP0TLLMn7/KuVOm4GlEVc6OvBNZuEzRriSYZ 156823459768092337875922818543729136404805918580285507923139232733465414368775678369646914249412830351437211620056021568154043505276475345347569200977945836210758870414054407438380975491139001471954448623922841964684437333066353208837709613982022690623722155151315252634380695513434502419141555410441456920089 AMc5H8kywLgiT4zz5xgoI90jejsHorbqUGtBeX9wke7zyvEKyWxRKScZwzRbinjDZzN48eg/30qTZOV2Rw97JFg+EA63iZ0vqfF8jErIt3hODniKX8zayCuNmiSb5kiZL0UDU1SNh8ER4m6o5vshBKkmqs0PeozfCGQtR3bZXlx4 139899247405256530335276706333424670310599977544642091674186635734421385499036688803073040921114325725234673132788498809189814711681909865484671959982394306416477300458309408833281654917008031099378445580498219376391819745965887864647387211647794422908411100892195529730435423964537342228510107659017578765432 AKv+3H/TruTX3wdMWnLzD05em8u/QMl6lCHT4VkK+uZwBXoLeji54Tcs/hZIhj0Bdj0URrRt+7JdGSTy4Sr986AtVFxBJZA3lT+JT4JSrq3oY1Tv+tX/yg8ZodQmbpQyyfaFg3BgeHNmsUoCrdqhj4IwBqEXoOBRIXnzaTuqqSEw 120779384043726135670909127168686589868907326577918074234323699599475436892003731971700278391108690400460261929381703781833059801757700386671579819341589048987186473249926590758009001670959004477454905417357202448886738669226760846888369186457452643053236389556969071303251275912453385963613554945645058007344 ANXIB+HxOyJd3YYsscMpqZpi/eYjZi5q6A0MohU4BiWEJK/E4uIObLJDH5yd4ng+hn7UMhc+R/AxG88hIdOc5NyG/QyFs95ZLUC26F9rkRifu2CBkgqR5EQi2cgwC8jGxQOkC62YND6cAn/ILsKTYaH0iavtO9Tz04vQp9Ypc82H 150122383481070201614242107655752525590609186454390549085509458064289390813495886095936526832230958746095739308601699615024239939948911472291507190108935262129646691795733786714291498653838550751365834947465294261687773081563139416397262227609481906371677917295227469553787085145970923979142676551778927103367 ZQLFoW+dJ7vrHdMlcLRGKY6T6PZKnE2L3NjXymS/55my2CDBLdDf3oXwLlRjVt9KnEiXyQzLhyY2PrFA4k3N/3P5lVDLHero5c36TMshbHgbIKRGN2CGWPEFeQ4j040IwVbQCPJeuF3jL5ikCxWZFXfeEnTL6TqumLfD9yLQfKA= 70932215714423143395949105745758445705072524008235214324766464113352968998429901322485575506330607802260244612268338586532462314021433435523464635419846126736185176246740838082062856583684393425704173881940108783636582561707441482446854068022535943408999200681879161519209676205165680598258447492092651404448 LzzvPw0FdtM2G/RRiqoajJiIH+Lw3jpL4H+08yOpp1bNITR2Aq0beu2nP0H4o2Z1/FNr2hzuGakkAhVbmmRXc8keoOkeaAQAP/8OYxHpjrqou3WPWaKx+vUCTSqVYYf8gnVKpAAC2cD+3lW+/ZJ538o+c0ovbUKNu1u1j1OBtA0= 33171669664542509840621265032202455391098253465550501094201777336478104142847268103467889435377685359857979277521589539506627375165485879405453566052091202280471235979376217319335800766353336252760793484157724210008639813552207624049019149744883918494762511376489708611103181576211531366514802868659603747853 APrGj1lIIlxA57DNh+bTEAFbJK2Y2P3MxLShb4fPx2aY6j88k3umoe07ISQLf9PzNPeml4/0I3w0KNd2x4s9KHbj7NsIT64lhO6eQSEteqZXZGXUYUyNzhrTbAjt+Q9LVKItQhsTkTW2HTQ5RQZfGrkL118b/I18J4P+T8CGZdDz 176100632478477421621142147788721746818712752858710594712903769452749028606541677227413333567013253138397373757811889654342173021761934591400685421771460440213093509170325205622261487145789848227404883040799927313402244625239515162996390018403365063394514244196976794479529075569412676472840544017222373593331 Fvcl/LemWk29I5LCjU1QedTjGlkvFF/kZXNkRJv+vNZ7qgq6pX8WB9yVkk6AoclDYAhCRfKTKuEpR23iafVuHpprPfNXcqBH8n01kq3U27xqIy2hS+D6BRBK67PQaekq31EB0aOcEb/DuNaXakS9+mtTMx6BKt+WoEY+NkzHK6c= 16126868736093163702771491576570380743773057522016869811780571865928979861357811080042796140032050364543242385458140594532945509386155523162799601656485075247603490060565663264947465987286983338572455184901756399862440455644131755848583379822279676555143231305246033911608913609591095831135803702269767527335 AKW8tvaB8YZ7J5W2lmquBniJzUhRfqFdPZPqvBoMzR4cRh1CMNdSFsYsnsaF3KolNzogdsxFpHAaEMG6zSvpNJAoi4nixCqb5SETXrSLASXvNjI9MvCoE2JCRq7kMbjPL7cem+mBPWZITGUI6KVlJPLxQngHYSFxukqlx7jznwJH 116384596458828069344020651216200368975621068920641012055593076864629080375946542748377736186556382088448816531408136815533164209947323588157210859294774679831647934533061547276394884474877353537242203645373945111105805934070657589374883764420038511061919092743520704686962593876316976299391579463759429567047 D5N2P4FrqDf7/2Z2BJsqah4SjUtolic/yNqdNzvNEogDKZKAJyGq4zhnHvkYXkEm2ueU/FDPJRqisszG0oULdU6c7p8acirEwsGLVh4RamnFRgmQSK1vbiYB3bR+P+iFX/bZ+TWjN2Y3YMa5UB//I6Zb5kEIjmTpjY2LEPI1e6s= 10937855369372570149476727082965401421189236366492771695094788039313362971972373068736123833330006002198346944149230147444718818161877123407713821100752433128205189334393732633989950841577315682292180735057952587083688644195300641998709155269462601925653013312848413290208844194513502358901613104779186502571 V/A1ktS0xrcwlI8xrYqvlLCFYrdVp8tEzZaZ9iNNpPH/pzVsA0WbnnUeHbdilkje+4OdoX9C4U2xaOuWOfvqLR0c7GeCkSffCqyf4ZsBmjy/BQL6rCpxMF0gIHXO5O8aJ1h17hy9LTuNzWm4zVh4pNFuHC9L6nAcf92udMiIQzk= 61752386563628388546439207444896778638632243226541303179646524864765343154194512297447627825411023405896612559648434895675553567405277169056807223959390559391191382555701580549902639604424290133917402316755076644943742815711432111554988540913643347167948778404861099845961151998728662878854088239266688156473 APoPgEKA0/r1FYmt/Iso6ChYK6dDU62Y+vH5h/LVE00biBYG1f7aL3GdllUTN+XQSHpqlDw8CD+9xojwZIMfgpgjOwLbbe7Aso460zLrg3R8aHBpbVt8iZUgjACwPYr5UyKbFzIAWaXcnYYQ+tCO9aDIuOz+/7eIF62C81zXFJVZ 175598490446477604563905754135475294999639698464908622773037381109011373179895295130424828038708319325919451724985361900259676699137657615076219968061941008972496322083528922054390781811699677037439989404270415929836486610353098273115864435328533577114470407444852521009919911888840405368858409835197558461785 cL54ymLJhRx3U20Y9aUTIsXy9Ags+XHy4qk3F7uJyO46eiXSL7VrrR9vTQXAbETbu1YiVWfslsPht810eUDUVaVir6yLnXkywn46Ci42FEvVoTEFjO22uYcCh8nqB8H589w/+lVSlNrcILugwfdfCvK1iZzVimOO6l3qzfXToOU= 79171550718114578361958369278761819285111811576818442980166457146638966315793211967882077899426611721874954146020093740153495693185472340728106727284441726113022873005252623222594060645383105757498856463065370975867121188445567981809371870213273555432308279508351518168027875538720367440153667708369625129189 QdQN4qW2QZq8/fmSaqlRiPSoDbhmF0oYjaY29HcKYGHdlOH0AMJb+RUIq1aszvVtjh7AYay2TNhaZMWQ6Qi3c42SNk3A1MVknT6zqiRCGjNFfxf/matbRLbTFQF832MAId708vrFLF/o2HpekMkc5hcHB6bkUUhEI1NLcMXwGck= 46226230186280253581676626651942823886592433541360244612432763620730826574920825070086312767146345247802570752482654580909236388357139147786783758670999083804670979821212991224400629053427330483809790366665043598754931511997925850227997764381723288657884346974360232490075739442406431704368767588177525348809 cxHvCK/dyVDvaqCCQyLeaiBGA36mV5el+1lc2eUTkHGUzX5gU0QQCEp+iSXNJhIOON8VFpKOFsziuV0Z+3cegWRw/VnxnjXcBh6IDKdupzOPB+Yl8MA1ti/GrQjLC6ikcNYNjQT0ZThL7KTqEvvZJH68WYmD0IuK26swjNGIGaI= 80804939616399473443737611589382762718815989847332356984276911837267997590368701684135326680567847542004499684038240485603420973682522792156533112356849436451918522884749244246467852622918805139990256619014116276456718693703261686778030658826952213058982142604346352178078750879100976710761147710018148637090 AIQ3OIZevkYoRGBmsFaXJobSfLeInuKKReVYNjP5VEPoMq0mXTltY6l09/rQ3d1JjsMD1PfA7emhxex+H9t3leBIfCi6Ux34GQEjXWpQc4awuiy9tbR077HaJyecvb8Qy1FTnOHoH5C043QJzrKYT/sFXjgB60piI8Y0R/hwxO4r 92845026347218330987427785323244729176754623818531419911990153715676845614711324345879159989637824921793015074978358052562420379797956750450245721653716740651389924718711940869162230097839047895842495414221110468446944827052871968998907462191349838598297775847512250220907563815783358238473966349820476321323 LoG6ib5lUh57rdmSkZSWzBoudytFohS4uoU/uly6OaQDOi34GeNVxu/yr6RszJyL9JWkGNgFaBIv/HirH5zA9VQAL/6kpL93a0/GQ/nuHkHy3GWZPF/2+yJ0PfazQ40fWhHZfRxBngWslbguFPjj1XaJ37YzpQAYb/+QcUai9ic= 32658152290878644668906121702816147999633088014476055330179597550087921141413344679134407016170035735846077181424615228657687216737432274043674411132745299610950657139041836412322040866250189120286839287690983293111362228893996267791120043532014262644480689231457941173330523718758287779526551822788227954215 AKu2jgOQCCfYZ3CLkXEH44aO4TtwMPeK/eq4FtNj9HZ9FxT0LLNJh0ZXPOaPJjgznvIw5C7/hNm7rUs1JeV8I8dj3nbS3EVERQz1gc/ckYB3H1bViWREOD5+TScDusi86YO/z4ar3dauKkg5kT1kKDuU/OP5kNMWvtJjHc4Vd3L3 120581042599355202025471829872601846477331097842315143148145881424071317426176264583672725691485724160094190478865850305422057632110749683552966861219554215519032344086824849470294473808177223497912069335635933312949412445851201918768630656712413082629164792850095444166888072453190903931430551124946191872759 ANLs7OsR7oBM5jSjVADrk+Mx9d0TeieTIkxwWiJ5STKNQmW2EzPOjgbfcLhbYEhzzDFJveXO2dzz6/c8V5oW2yqg7VMx88DzEbpQnQpk/rOQRw9jbI4fxXNJHkNZCeysEVvFfLJb4ecsGA0xJ3Aylny/jP10ahPv2z5K99edGZSU 148116916208650944522110872759145096907599612943009577897396622287067669897712748449324334650112672914917664881091633448764667172850435775162090891556266912697811031318228334453406561952979778127173704706529448647577013482442758465809198730066784986763500579667100246958959793527011919373534159474250508506260 AL+Er3n1qj+SBsZVtOMJYg4m0CN+DE6gRnC1F7nPvd2XnBe+QE0+LKfcpUDHVNxoydW4BDzNVwnUNbyjXZ+iuddPtO9hchVEI36UiuL0ydeldFpOZ9mtHJaAF6abd0MlHw4vXRf8CbOvXb5N4s76ggijlZBjRtU563sSmBcyq6Zt 134488725667189507159811764480908602790838430340670328479145818969651133017546803581865897303917708192047926432630297993507146075655594931523561067937580218599890162311074002344315818494246433967228889645359283635389151927472221799543158424012020308449895562192866672439712148770104592027035768027605661099629 AK/04XOBSjjPpuFXTDF82RNWnKqZz9mJQbS2B5bn0ehFnBa6j+B+MazX+AxXTL/d5+hPLT1uexcnSMl3DcGGwKipOXg7Dtuj3pfJXHTrCqXAUYrIXI+8vKVQO55yQPGfzIg9SVgetwW1sDk+a28ZhJ5a9OddqNoi5C+dLce7ZtNb 123560902006294001923570614486104726169564351074482936927091682096999779538353161007361361829586988452098646362280351148131540524964916445100589671458589346440250329883789099771417949746709217272531950438336245613419967556433467843237384555807236658182067742367748737224684334525934210197178231424396818830171 PzOEGHlihiveoWFAALY+LOfkRJfm0NUF/uR6cSU/tbpGAq4onNpr+iZIzEP5o3JBLOtDC595/NBPI0fzaXl0vQvgJs6KG8iKANjsLKQjIpZBkoKhdbG9MzTVQuAeuDW0w3sn2iMZ/v2dgAzRwfqmQYXJr3I2BbcwWraIJuZXw5A= 44381416070253681813077725822442106641846565789204187691647505370231831464947935035197059366680327425453811558282831465960889061956588244308214943856009686127871667376028831540813257349779756631357122923723235595360268572998278795110672666089470210929411514949652537714634611421849780859192966935514197771152 APnuduN01GS9dO2m2uCLs400AR2lX7elOnIPC5U6e17qbukxWYzNhilZlM4kdGXAIeYpzFdSIW/gxRMZe6TXq9krFWRaaPyT2QwRfGHYnazS9F1QNYmW1zXdt+qVp0JGxmh5PyDstbP8Z3x50/E8Mb0gLLPhNAvzY2Jnr9A8Q1Hy 175507868985304663005133968393406051624825489142498103948374797086106732382869120248515993626061853699363294022457032257026588816021007648668265488426495800459085474654859258116280251546902009156490112550154951965894022789029787886785376415437170872937201839249103828294508088966180386198213606090453461193202 QHEhL4iVzNdUsfG0izTEepwTOvxka8t/9MwuF1Ey6kxsI+ry4g4sJPgR2xMnbtOmvQn2NitAkfvA8JPCiL7a8+gmf+DVRDjKDfpfrtgAVmo+3rH+uJYTrKhAp8R7ggU2xIrvbIrgeUj7ieThPI3Rtap+IdkPCL853JC/+oKtytM= 45252649968839515171157821292772647085425694172492111870169593872127007254353374581972876464918186509502070064028725519394859148593053614163356612260257013360168930649423732336969778875205250872728821432415158634190866775855521719727700464116412886964736859295086745723651735554245035077902615220578218265299 APeaekK4mVhEShCfM0mkRebcg1Iq5CgrFIEGOoh1nHzgebr5A9Wrhm9yD1Vd3e+fFD9urDRB4y5MHPJHX1U2NFToC+H8nQkFXL8bfd/9Wl2c7y8m0Mxwi53pLIdzETLbbfeOOtJvuSYYT3n8+/PeMnJ46UD8OfqtnFuS0/bVpFLS 173873040145444066957050580959132871919216036714423404143335635770937773583761934638398867981658394368476005882852706046614562314432695052874974848076542261910660410561876043187368112065303981001507235893831108658530338308496461162623683138693880482650786841100027392293758260448606244283355655751440485602002 FqC/wgZDPTUoObPFSH5w4QR79zj/O+ZiHGTEnsBMwNZD3Gl/ClRDIsFMDDupNLgwgXsqCQbpwSOHOtAvUuAFwRpzt5B7lwIgtP5ism/AZRno5p+9WVSmUAM3glHsNtvYydz2MkXtnXzSMIR1ZVoLrdwMnckE4pbMzggqz+JZqxw= 15889870005716350976759704672045310928616256175405784574141006779373730686049218680335525720670897894546334915362899913262232170795516176419192840427996647372619000239408311568577050460995518058850793096827271653902583271225799114408537346367483775593212272587811309978019791973449354003275559762102731778844 AJXNbv2AMWadF5h99ZAUy5gLnVK/hMaakFo0ZedtPNRJobxPmwj+h52G+Czd0U48G0V0wpdeUJC9v/4BhjzhCvNhNsdAT1+vQXDuteYQ1aspsEKLQ6b+NknO88QSbRJw53+KeOY2xe7PKOa4V89XnFFBF7wljRnIYrM8vvcqVQDk 105194875227030598769888785590198577650278341586165110611689226597424766274486797264032300493674927704016605741286512271390703088626381669060095573361828932336327125438452066548897528158329044309005232090053420259033538936293519762277428283316506398965916381374819450858053512398634116052299066189424983605476 AIDRnUpBHepjBqYAlU4MG/8JxzX1mPxVNHpWvnEVgvqTQx/bisFPpXrYs3jAKIR/lzevYwhH0K/8Vvw4NK9iTMFqgSnU44AZztKsoxUXsEsl1UU56UscY5C7ciKU6vjjWI7nm/uHNOXdE82TQXkk2WX8ferNqZU5DaLFCb+zxb7w 90459642084794142567976043425270153270545560059973413835786695756473295513758287577749768786155290305189883600338986370836806413936196854410098516254596146039255388020628703824195128439558127783534033672712705194483515442668075394018677699876614329419492391568463215822656901183478205197671375262145069825776 AIdvVNzJqWPgAShvi3GhbhMQft+SLigKGrhoqas2Saz/bA9u9Td6fAxa2LjrAqshW6cnm2aalc3Yv6RW/Y8vg7Ho31NSaRjT4zMUenykcC0/Y88UNxREi85wdnHwGytms6Lq49H8/7EFGJIyL1PLRWPmZn6XFkegscI/HUq/hiKm 95105613103051650721863964216778532448106311156426028879315612217763044797186635476805213120469258258125661666950525364331551671653846368977016286153840829836509696804585927581668281228810410814602664419962214359687545209312836366693384158782798559255789953908588601637765910472073600954502095647132310971046 DdchOPjXrI6lpV84IdKCisPmdqZan8AARXRLADEhixsfXCYuO+WhNatI/fM1vgv+/TxwwIQjIfG1vOZcB36JUfjHYdItYQ70vUXaVFdpqvoBGyfOTU50Ds/11iGPCF8mWiQwR30/XAXytqDZtaVJVWsgHD3RigBSnSHhnvZAWYg= 9719024770319024562623340689338530708271347986326272393419504304391837979619189392867902307307106771234732135400958362219711925045600118964223238147375808749507928768896918369395426933218443166133187066167663170936604731896932630589251946733237697936733924510107175304126061649311812536190882160340308613512 I+Z6rdTOt26/v3dtUP1plITb15fjb6aMDvqFS3AD1+nxBqnnk7ISGE9j6dv762EIWQpMzcCG5NCCq35KOHEwRXP28zup6olOMt3CBFgYVcBE2pWOpGiO19G/iFweYZXZPY5HgIkex7HBbb7l6HhomPc2sLL/IRhh2oogyHx2JMM= 25210054612455888156900839678249806510561198051210010474517915819801056434402727631042894881559517808906460418029149538469607239850657781476308872923928122553395468026744382526167194202058040459679991391557937527079948356545086684521068912222036707113005006607012596093923970784177288565193670152033981048003 ALbBoyelCs4UkfnPjMT3S67ujhBHBEE0uxLx6kSGZq2IOMU/QdWYPFElRgYC/y++334FSEycjS6NAJJo2ITpZCO5AjNJ93J3WYgbDLiwu1VzKHX6ItfFNEk45km+QTi07+pDKcKNd1k0mxqpLd/PuZd5hRpPDDoKBb6i+mrCb2yF 128335905497646745013379107761994003743181143126608677203818152878840562628631384684712779135591095534911406031545494164782375276574093777950840330452805743803067864740000758175436633463846967335728314347497013853264454015790847388463800323796888198433722196292529074568758149650782323407298620158495364705413 ANwlxEkeqmqYTxw1ZwMi1v2wo4ntPaEYZYoTLTJQfa+kuIksnHW9va243HAiOixd+rviVdm1dEwzESBbX0wiJNtRBpP+bnRxy4xOBjNoOB0c/tfka5JVwu5eeskyHx4V3inLviUaj86Yck42n5NaJFMfBvhzVftZ/YF9WBITI8g6 154592850289860621115358362871905683265658659789986179554827712019629689749439795961607030363152337159590319622241556795951071651584979664762468782303706550885785493534656062553770262954861884613383561063525714923031691298088562054236178003658891902606245782350998076658704876516153027797371814038658244397114 ================================================ FILE: test/data/test1-discover.txt ================================================ equiv Status: 200 OK Content-Type: text/html Joe Schmoe's Homepage

    Joe Schmoe's Homepage

    Blah blah blah blah blah blah blah

    header Status: 200 OK Content-Type: text/html YADIS_HEADER: URL_BASE/xrds Joe Schmoe's Homepage

    Joe Schmoe's Homepage

    Blah blah blah blah blah blah blah

    xrds Status: 200 OK Content-Type: application/xrds+xml xrds_ctparam Status: 200 OK Content-Type: application/xrds+xml; charset=UTF8 xrds_ctcase Status: 200 OK Content-Type: appliCATION/XRDS+xml xrds_html Status: 200 OK Content-Type: text/html redir_equiv Status: 302 Found Content-Type: text/plain Location: URL_BASE/equiv You are presently being redirected. redir_header Status: 302 Found Content-Type: text/plain Location: URL_BASE/header You are presently being redirected. redir_xrds Status: 302 Found Content-Type: application/xrds+xml Location: URL_BASE/xrds redir_xrds_html Status: 302 Found Content-Type: text/plain Location: URL_BASE/xrds_html You are presently being redirected. redir_redir_equiv Status: 302 Found Content-Type: text/plain Location: URL_BASE/redir_equiv You are presently being redirected. lowercase_header Status: 200 OK Content-Type: text/html x-xrds-location: URL_BASE/xrds Joe Schmoe's Homepage

    Joe Schmoe's Homepage

    Blah blah blah blah blah blah blah

    404_server_response Status: 404 Not Found EEk! 500_server_response Status: 500 Server error EEk! 201_server_response Status: 201 Created EEk! 404_with_header Status: 404 Not Found YADIS_HEADER: URL_BASE/xrds EEk! 404_with_meta Status: 404 Not Found Content-Type: text/html Joe Schmoe's Homepage

    Joe Schmoe's Homepage

    Blah blah blah blah blah blah blah

    ================================================ FILE: test/data/test1-parsehtml.txt ================================================ found found found found found found found found None