Skip to content
Browse files

Merge "CFID 325 - Ruby login server for the UAA"

  • Loading branch information...
2 parents ae43346 + 0ab4378 commit c22e65fd40d5dfa7d004cccfa49e1f8b6a4eae87 @joeldsa joeldsa committed with Gerrit Code Review
Showing with 1,026 additions and 0 deletions.
  1. +8 −0 samples/ruby-login-server/Gemfile
  2. +34 −0 samples/ruby-login-server/Gemfile.lock
  3. +86 −0 samples/ruby-login-server/README.md
  4. +12 −0 samples/ruby-login-server/config.ru
  5. +234 −0 samples/ruby-login-server/login.rb
  6. +94 −0 samples/ruby-login-server/openid_login.rb
  7. +101 −0 samples/ruby-login-server/public/css/openid-shadow.css
  8. +69 −0 samples/ruby-login-server/public/css/openid.css
  9. BIN samples/ruby-login-server/public/images.large/aol.gif
  10. BIN samples/ruby-login-server/public/images.large/facebook.gif
  11. BIN samples/ruby-login-server/public/images.large/google.gif
  12. BIN samples/ruby-login-server/public/images.large/mailru.gif
  13. BIN samples/ruby-login-server/public/images.large/myopenid.gif
  14. BIN samples/ruby-login-server/public/images.large/openid.gif
  15. BIN samples/ruby-login-server/public/images.large/rambler.gif
  16. BIN samples/ruby-login-server/public/images.large/verisign.gif
  17. BIN samples/ruby-login-server/public/images.large/vkontakte.gif
  18. BIN samples/ruby-login-server/public/images.large/yahoo.gif
  19. BIN samples/ruby-login-server/public/images.large/yandex.gif
  20. BIN samples/ruby-login-server/public/images.small/aol.ico
  21. BIN samples/ruby-login-server/public/images.small/aol.ico.gif
  22. BIN samples/ruby-login-server/public/images.small/aol.ico.png
  23. BIN samples/ruby-login-server/public/images.small/blogger.ico
  24. BIN samples/ruby-login-server/public/images.small/blogger.ico.gif
  25. BIN samples/ruby-login-server/public/images.small/blogger.ico.png
  26. BIN samples/ruby-login-server/public/images.small/claimid.ico
  27. BIN samples/ruby-login-server/public/images.small/claimid.ico.gif
  28. BIN samples/ruby-login-server/public/images.small/claimid.ico.png
  29. BIN samples/ruby-login-server/public/images.small/clickpass.ico
  30. BIN samples/ruby-login-server/public/images.small/clickpass.ico.gif
  31. BIN samples/ruby-login-server/public/images.small/clickpass.ico.png
  32. BIN samples/ruby-login-server/public/images.small/facebook.ico
  33. BIN samples/ruby-login-server/public/images.small/facebook.ico.gif
  34. BIN samples/ruby-login-server/public/images.small/facebook.ico.png
  35. BIN samples/ruby-login-server/public/images.small/flickr.ico
  36. BIN samples/ruby-login-server/public/images.small/flickr.ico.gif
  37. BIN samples/ruby-login-server/public/images.small/flickr.ico.png
  38. BIN samples/ruby-login-server/public/images.small/google.ico
  39. BIN samples/ruby-login-server/public/images.small/google.ico.gif
  40. BIN samples/ruby-login-server/public/images.small/google.ico.png
  41. BIN samples/ruby-login-server/public/images.small/google_profile.ico
  42. BIN samples/ruby-login-server/public/images.small/google_profile.ico.gif
  43. BIN samples/ruby-login-server/public/images.small/google_profile.ico.png
  44. BIN samples/ruby-login-server/public/images.small/launchpad.ico
  45. BIN samples/ruby-login-server/public/images.small/launchpad.ico.gif
  46. BIN samples/ruby-login-server/public/images.small/launchpad.ico.png
  47. BIN samples/ruby-login-server/public/images.small/linkedin.ico
  48. BIN samples/ruby-login-server/public/images.small/linkedin.ico.gif
  49. BIN samples/ruby-login-server/public/images.small/linkedin.ico.png
  50. BIN samples/ruby-login-server/public/images.small/livejournal.ico
  51. BIN samples/ruby-login-server/public/images.small/livejournal.ico.gif
  52. BIN samples/ruby-login-server/public/images.small/livejournal.ico.png
  53. BIN samples/ruby-login-server/public/images.small/mailru.ico
  54. BIN samples/ruby-login-server/public/images.small/mailru.ico.gif
  55. BIN samples/ruby-login-server/public/images.small/mailru.ico.png
  56. BIN samples/ruby-login-server/public/images.small/myopenid.ico
  57. BIN samples/ruby-login-server/public/images.small/myopenid.ico.gif
  58. BIN samples/ruby-login-server/public/images.small/myopenid.ico.png
  59. BIN samples/ruby-login-server/public/images.small/openid.ico
  60. BIN samples/ruby-login-server/public/images.small/openid.ico.gif
  61. BIN samples/ruby-login-server/public/images.small/openid.ico.png
  62. BIN samples/ruby-login-server/public/images.small/rambler.ico
  63. BIN samples/ruby-login-server/public/images.small/rambler.ico.gif
  64. BIN samples/ruby-login-server/public/images.small/rambler.ico.png
  65. BIN samples/ruby-login-server/public/images.small/technorati.ico
  66. BIN samples/ruby-login-server/public/images.small/technorati.ico.gif
  67. BIN samples/ruby-login-server/public/images.small/technorati.ico.png
  68. BIN samples/ruby-login-server/public/images.small/twitter.ico
  69. BIN samples/ruby-login-server/public/images.small/twitter.ico.gif
  70. BIN samples/ruby-login-server/public/images.small/twitter.ico.png
  71. BIN samples/ruby-login-server/public/images.small/verisign.ico
  72. BIN samples/ruby-login-server/public/images.small/verisign.ico.gif
  73. BIN samples/ruby-login-server/public/images.small/verisign.ico.png
  74. BIN samples/ruby-login-server/public/images.small/vidoop.ico
  75. BIN samples/ruby-login-server/public/images.small/vidoop.ico.gif
  76. BIN samples/ruby-login-server/public/images.small/vidoop.ico.png
  77. BIN samples/ruby-login-server/public/images.small/vkontakte.ico
  78. BIN samples/ruby-login-server/public/images.small/vkontakte.ico.gif
  79. BIN samples/ruby-login-server/public/images.small/vkontakte.ico.png
  80. BIN samples/ruby-login-server/public/images.small/winliveid.ico
  81. BIN samples/ruby-login-server/public/images.small/winliveid.ico.gif
  82. BIN samples/ruby-login-server/public/images.small/winliveid.ico.png
  83. BIN samples/ruby-login-server/public/images.small/wordpress.ico
  84. BIN samples/ruby-login-server/public/images.small/wordpress.ico.gif
  85. BIN samples/ruby-login-server/public/images.small/wordpress.ico.png
  86. BIN samples/ruby-login-server/public/images.small/yahoo.ico
  87. BIN samples/ruby-login-server/public/images.small/yahoo.ico.gif
  88. BIN samples/ruby-login-server/public/images.small/yahoo.ico.png
  89. BIN samples/ruby-login-server/public/images.small/yandex.ico
  90. BIN samples/ruby-login-server/public/images.small/yandex.ico.gif
  91. BIN samples/ruby-login-server/public/images.small/yandex.ico.png
  92. BIN samples/ruby-login-server/public/images/openid-inputicon.gif
  93. BIN samples/ruby-login-server/public/images/openid-providers-en.png
  94. BIN samples/ruby-login-server/public/images/openid-providers-ru.png
  95. +32 −0 samples/ruby-login-server/public/js/jquery-1.2.6.min.js
  96. +96 −0 samples/ruby-login-server/public/js/openid-en.js
  97. +202 −0 samples/ruby-login-server/public/js/openid-jquery.js
  98. +11 −0 samples/ruby-login-server/views/confirm.erb
  99. +47 −0 samples/ruby-login-server/views/login.erb
View
8 samples/ruby-login-server/Gemfile
@@ -0,0 +1,8 @@
+source :rubygems
+
+gem "sinatra"
+gem "rest-client"
+gem "yajl-ruby"
+gem "sequel"
+gem "ruby-openid"
+gem "thin"
View
34 samples/ruby-login-server/Gemfile.lock
@@ -0,0 +1,34 @@
+GEM
+ remote: http://rubygems.org/
+ specs:
+ daemons (1.1.8)
+ eventmachine (0.12.10)
+ mime-types (1.18)
+ rack (1.4.1)
+ rack-protection (1.2.0)
+ rack
+ rest-client (1.6.7)
+ mime-types (>= 1.16)
+ ruby-openid (2.1.8)
+ sequel (3.34.1)
+ sinatra (1.3.2)
+ rack (~> 1.3, >= 1.3.6)
+ rack-protection (~> 1.2)
+ tilt (~> 1.3, >= 1.3.3)
+ thin (1.3.1)
+ daemons (>= 1.0.9)
+ eventmachine (>= 0.12.6)
+ rack (>= 1.0.0)
+ tilt (1.3.3)
+ yajl-ruby (0.8.3)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ rest-client
+ ruby-openid
+ sequel
+ sinatra
+ thin
+ yajl-ruby
View
86 samples/ruby-login-server/README.md
@@ -0,0 +1,86 @@
+# Login Sample Application
+
+This login application is a sample for how you can set up your own custom login user interface using the UAA as a backend Identity Provider. The application also supports different openid identity providers. The application is written in ruby and uses the sinatra framework. You may choose to embed it along with your code to provide a customized look and feel for the login interface using the UAA as an identity provider and a token server to issue Oauth access tokens.
+
+## Quick start
+
+Start your UAA
+
+ $ git clone git@github.com:cloudfoundry/uaa.git
+ $ cd uaa
+ $ mvn install
+ $ mvn tomcat:run
+
+Verify that the uaa has started by going to http://localhost:8080/uaa
+
+Start the sample login application
+
+ $ cd samples/ruby-login-server
+ $ bundle install
+ $ bundle exec thin start
+ >> Using rack adapter
+ I, [2012-06-14T14:54:46.273942 #5369] INFO -- : Using token server http://localhost:8080/uaa
+ >> Thin web server (v1.3.1 codename Triple Espresso)
+ >> Maximum connections set to 1024
+ >> Listening on 0.0.0.0:3000, CTRL+C to stop
+
+You can start the oauth flow with a HTTP GET request to http://localhost:3000/oauth/authorize?client_id=app&response_type=code&scope=openid&redirect_uri=http://foo.com
+
+Login with the pre-created UAA user/password of "marissa/koala"
+
+## Customizing the application
+
+### Using a different token server
+
+The back end UAA token server URL can be customized by setting the UAA_TOKEN_SERVER environment variable
+This application also uses the login client to support logging in with authenticated email addresses from OpenID providers. The secret for the login client can be customized by
+setting the LOGIN_CLIENT_SECRET environment variable
+
+For details on the login client, please refer to the UAA.
+
+Each of these variables default to the values for a locally hosted UAA.
+
+### Customizing the user interface
+
+There are two ruby templates that can be customized for look and feel to match your application. These are login.erb used to display the login interface and confirm.erb used to display the authorization confirmation page.
+
+### Logging
+
+Before using this as a sample, please configure the application logging to ensure that no confidential information is logged.
+
+## Playing with the entire flow
+
+You may write a simple sinatra client application to test the end to end flow as follows. This client also uses application defaults for a locally hosted UAA. It logs the user into the UAA and displays a UAA access token if the login succeeds
+
+ require 'sinatra'
+ require 'yajl'
+ require 'restclient'
+ require 'base64'
+
+ LOGIN_SERVER_URL = ENV['LOGIN_SERVER_URL'] || "http://localhost:3000"
+ UAA_TOKEN_SERVER = ENV['UAA_TOKEN_SERVER'] || "http://localhost:8080/uaa"
+ CLIENT_SECRET = ENV['CLIENT_SECRET'] || "appclientsecret"
+
+ get '/' do
+ "<html><body><a href=\"#{LOGIN_SERVER_URL}/oauth/authorize?client_id=app&response_type=code&scope=openid&redirect_uri=#{request.scheme}://#{request.host_with_port}/done\"\">Login</a></body></html>"
+ end
+
+ get '/done' do
+ code = params[:code]
+ $logger = Logger.new(STDOUT)
+ RestClient.log = $logger
+ response = RestClient.post("#{UAA_TOKEN_SERVER}/oauth/token", {"grant_type" => "authorization_code", "code" => "#{code}", "redirect_uri" => "#{request.scheme}://#{request.host_with_port}/done"}, {:accept => :json, :authorization => "Basic #{Base64.strict_encode64("app:#{CLIENT_SECRET}")}"}) \
+ {|response, request, result, &block| response}
+ puts "#{response.body.inspect}"
+
+ begin
+ access_token = Yajl::Parser.new.parse(response.body)["access_token"]
+ decoded_token = Base64.decode64(access_token.split('.')[1])
+ "Access Token from UAA is #{access_token} \
+ <br /><br />Decoded token is #{decoded_token} \
+ <br /><br /><a href=\"#{LOGIN_SERVER_URL}/logout\">Logout</a>"
+ rescue => e
+ puts "#{e.backtrace}"
+ "Could not fetch access token"
+ end
+ end
View
12 samples/ruby-login-server/config.ru
@@ -0,0 +1,12 @@
+$:.unshift(".")
+
+require 'login'
+require 'openid_login'
+
+map "/openid" do
+ run OpenIdLoginApplication.new
+end
+
+map "/" do
+ run LoginApplication.new
+end
View
234 samples/ruby-login-server/login.rb
@@ -0,0 +1,234 @@
+require 'sinatra/base'
+require 'restclient'
+require 'yajl'
+require 'logger'
+require 'base64'
+
+# The LoginApplication class handles the oauth
+# authorization flow for the CloudFoundry UAA
+class LoginApplication < Sinatra::Base
+ enable :sessions
+
+ # URL of the uaa token server
+ UAA_TOKEN_SERVER = ENV['UAA_TOKEN_SERVER'] || "http://localhost:8080/uaa"
+ # Client secret of the login client. The login client allows this
+ # application to authenticate to the token endpoint to get an access token
+ # for a pre-authenticated email address (for the case when a pre-authenticated
+ # email address is received by this application from an OpenID provider)
+ LOGIN_CLIENT_SECRET = ENV['LOGIN_CLIENT_SECRET'] || "loginsecret"
+
+ # Handles requests to the /login endpoint.
+ # If an authenticated user session already exists with the authorization server,
+ # the user is redirected to a confimation page
+ get '/login' do
+ pass unless params[:email].nil?
+
+ # If there is already a session with the uaa, the user has been authenticated
+ if uaa_session?(request).nil?
+ erb :login
+ else
+ redirect '/confirm'
+ end
+ end
+
+ # The start of the oauth flow for the client application
+ get '/oauth/authorize' do
+ if params.nil? || params.empty?
+ halt 404
+ end
+
+ # Store the request parameters in session
+ [:client_id, :response_type, :scope, :redirect_uri, :state].each{|param| session[param] = params[param.to_s]}
+ $logger.debug("Saving request parameters #{session.inspect}")
+
+ # Redirect the user to the login page if no session
+ # is available with the uaa
+ if uaa_session?(request).nil?
+ redirect '/login'
+ else
+ redirect '/confirm'
+ end
+ end
+
+ # Common login flow for incoming username and password credentials
+ # or incoming authenticated email addresses
+ login = lambda do
+ username = request[:username]
+ password = request[:password]
+
+ uaa_response = nil
+ unless username.nil? && password.nil?
+ # Post the credentials and get a session with the uaa. Save the uaa cookie
+ uaa_response = post("#{UAA_TOKEN_SERVER}/login.do", \
+ {"username" => username, "password" => password})
+ $logger.debug "#{uaa_response.headers.inspect}"
+ else
+ # Get the email address from the openid provider and ask for authorization directly
+ email = session[:authenticated_email]
+ $logger.debug "authenticated email address #{email}"
+ # Post the credentials and get a session with the uaa. Save the uaa cookie
+ uaa_response = post_to_authorize({"login" => "#{Yajl::Encoder.encode("username" => email)}"}, \
+ {:authorization => "bearer #{login_access_token()}"})
+ $logger.debug "#{uaa_response.headers.inspect}"
+ end
+
+ # If the response from the UAA is a redirect ending in error=true, authentication has failed
+ if uaa_response.headers[:location] =~ /\?error=true/
+ redirect '/login?error=true'
+ end
+
+ if uaa_response.nil?
+ $logger.debug("Could not establish session with the uaa")
+ redirect '/login?error=true'
+ end
+
+ # Maintain the cookie with the uaa
+ uaa_cookie = uaa_response.cookies["JSESSIONID"]
+ $logger.debug "UAA Cookie #{uaa_cookie}"
+ response.set_cookie("uaa_cookie", uaa_cookie)
+
+ redirect '/confirm'
+ end
+
+ # A similar authorization flow is implemented for the uaa as well as openid flows
+ get '/authenticatedlogin', &login
+ post '/login', &login
+
+ # Handles authorization confirmation flow
+ get '/confirm' do
+ cookie = uaa_session?(request)
+ $logger.debug("Current values in session #{session.inspect}")
+ unless cookie.nil?
+ [:client_id, :response_type, :scope, :redirect_uri].each do |parameter| \
+ unless session[:parameter].nil?
+ halt 400, "Invalid request. User authenticated but unable to find \"#{parameter}\" parameter \
+ from request. Please see README for directions."
+ end
+ end
+ # Maintaining the UAA cookie from the successful login to the uaa,
+ # post to the /oauth/authorize endpoint to get the confirmation data
+ request_params = {"client_id" => session[:client_id],
+ "response_type" => session[:response_type],
+ "scope" => session[:scope],
+ "redirect_uri" => session[:redirect_uri]}
+ request_params["state"] = session[:state] unless session[:state].nil?
+ uaa_response = post_to_authorize(request_params, {:cookies => { :JSESSIONID => cookie}})
+ $logger.debug "#{uaa_response.inspect}"
+ case uaa_response.code
+ when 200
+ confirmation_info = Yajl::Parser.new.parse(uaa_response.body)
+ $logger.debug "#{confirmation_info.inspect}"
+ session[:confirm_key] = (confirmation_info["options"]["confirm"]["key"] \
+ if confirmation_info["options"] && confirmation_info["options"]["confirm"]) || "user_oauth_approval"
+
+ erb :confirm, :locals => {:client_id => confirmation_info["authorizationRequest"]["clientId"], \
+ :scopes => confirmation_info["authorizationRequest"]["scope"]}
+ when 302
+ # Access confirmation not required, get the code.
+ $logger.debug "#{uaa_response.headers[:location]}"
+
+ redirect uaa_response.headers[:location]
+ else
+ halt 500, "error from the token server #{uaa_response.inspect}"
+ end
+ else
+ halt 500, "invalid state"
+ end
+ end
+
+ # User confirms / denies authorization
+ post '/confirm' do
+ choice = params[:choice]
+ $logger.debug "#{choice}"
+
+ target = '/login'
+
+ # User confirms authorization
+ if choice == "yes"
+ cookie = request.cookies['uaa_cookie']
+
+ # Post confirmation to the uaa and redirect to the target
+ request_params = {"client_id" => session[:client_id],
+ "response_type" => session[:response_type],
+ "scope" => session[:scope],
+ "redirect_uri" => session[:redirect_uri],
+ session[:confirm_key] => "true"}
+ request_params[:state] = session[:state] unless session[:state].nil?
+ uaa_response = post_to_authorize(request_params, {:cookies => { :JSESSIONID => cookie}})
+ $logger.debug "#{uaa_response.headers[:location]}"
+ target = uaa_response.headers[:location]
+ else
+ cleanup(response)
+ end
+
+ redirect target
+ end
+
+ get '/logout' do
+ cleanup(response)
+ end
+
+ helpers do
+ def uaa_session?(request)
+ cookie = request.cookies['uaa_cookie']
+ $logger.debug("Found uaa session cookie #{cookie}")
+ unless cookie.nil?
+ $logger.debug "cookie value #{cookie}"
+ response = post_to_authorize(nil, {:cookies => { :JSESSIONID => cookie}})
+ $logger.debug("uaa_session #{response.headers.inspect}")
+ if response.code == 302 && response.headers[:location] =~ /\/login/
+ cookie = nil
+ end
+ end
+ cookie
+ end
+
+ def cleanup(response)
+ response.delete_cookie('uaa_cookie')
+ session.clear
+ end
+
+ def post_to_authorize(request_params, headers)
+ headers = headers.merge(:accept => :json)
+
+ $logger.debug("Headers to post to authorize #{headers}")
+
+ post("#{UAA_TOKEN_SERVER}/oauth/authorize", request_params, headers)
+ end
+
+ def login_access_token
+ # Get an access token for the login client
+ login_response = post("#{UAA_TOKEN_SERVER}/oauth/token", \
+ {"response_type" => "token", "grant_type" => "client_credentials"}, \
+ {:accept => :json, :authorization => "Basic #{Base64.strict_encode64("login:#{LOGIN_CLIENT_SECRET}")}"})
+ $logger.debug "#{login_response.body.inspect}"
+ access_token = Yajl::Parser.new.parse(login_response.body)["access_token"]
+ end
+
+ def post(url, content, headers = nil)
+ begin
+ response = RestClient.post(url, content, headers) \
+ {|response, request, result, &block| response}
+ rescue => e
+ $logger.error("Error connecting to #{url}, #{e.backtrace}")
+ halt 500, "UAA unavailable."
+ end
+ end
+ end
+
+ configure :development do
+ $logger = Logger.new(STDOUT)
+ RestClient.log = $logger
+ $logger.info("Using token server #{UAA_TOKEN_SERVER}")
+ end
+
+ configure :production do
+ $logger = Logger.new(STDOUT)
+ $logger.info("Using token server #{UAA_TOKEN_SERVER}")
+ end
+
+ get '/' do
+ redirect '/login'
+ end
+
+end
View
94 samples/ruby-login-server/openid_login.rb
@@ -0,0 +1,94 @@
+require 'sinatra/base'
+require 'logger'
+require 'pathname'
+require 'openid'
+require 'openid/extensions/ax'
+require 'openid/store/filesystem'
+
+# The OpenIdLoginApplication class handles the oauth
+# authorization flow for OpenID providers
+class OpenIdLoginApplication < Sinatra::Base
+ enable :sessions
+
+ # Start of the openid flow
+ get '/start' do
+ begin
+ identifier = params[:openid_identifier]
+ if identifier.nil?
+ $logger.error("No identifier found")
+ redirect '/login?error=true'
+ end
+ oidreq = consumer.begin(identifier)
+ rescue OpenID::OpenIDError => e
+ $logger.error "Discovery failed for #{identifier}: #{e}"
+ redirect '/login?error=true'
+ end
+
+ # Fetch the email address from the openid provider
+ fetch_request = OpenID::AX::FetchRequest.new
+ fetch_request.add(OpenID::AX::AttrInfo.new("http://axschema.org/contact/email", "email", true))
+ oidreq.add_extension(fetch_request)
+
+ url = server_url(request)
+ return_to = "#{url}/openid/complete"
+ realm = "#{url}"
+
+ redirect oidreq.redirect_url(realm, return_to)
+ end
+
+ # End of the openid flow
+ get '/complete' do
+ oidresp = consumer.complete(params, request.url)
+ $logger.debug("oidresp #{oidresp.inspect}")
+ case oidresp.status
+ when OpenID::Consumer::FAILURE
+ if oidresp.display_identifier
+ $logger.error("Verification of #{oidresp.display_identifier}"\
+ " failed: #{oidresp.message}")
+ else
+ $logger.error("Verification failed: #{oidresp.message}")
+ end
+ when OpenID::Consumer::SUCCESS
+ $logger.info("Verification of #{oidresp.display_identifier}"\
+ " succeeded.")
+
+ email_extension = oidresp.extension_response("http://openid.net/srv/ax/1.0", false)
+ email = email_extension["value.email"]
+ $logger.debug("authenticated email from openid provider #{email}")
+ session[:authenticated_email] = email
+ redirect "/authenticatedlogin"
+ when OpenID::Consumer::SETUP_NEEDED
+ $logger.error("Immediate request failed - Setup Needed")
+ when OpenID::Consumer::CANCEL
+ $logger.error("OpenID transaction cancelled.")
+ else
+ $logger.error("Unknown error #{oidresp.status.inspect}")
+ end
+ redirect '/login?error=true'
+ end
+
+ helpers do
+ def server_url(request)
+ "#{request.scheme}://#{request.host_with_port}"
+ end
+ end
+
+ configure :development do
+ $logger = Logger.new(STDOUT)
+ end
+
+ configure :production do
+ $logger = Logger.new(STDOUT)
+ end
+
+ private
+
+ def consumer
+ if @consumer.nil?
+ dir = Pathname.new(File.dirname( __FILE__)).join('db').join('cstore')
+ store = OpenID::Store::Filesystem.new(dir)
+ @consumer = OpenID::Consumer.new(session, store)
+ end
+ return @consumer
+ end
+end
View
101 samples/ruby-login-server/public/css/openid-shadow.css
@@ -0,0 +1,101 @@
+/*
+ Simple OpenID Plugin
+ http://code.google.com/p/openid-selector/
+
+ This code is licensed under the New BSD License.
+*/
+
+#openid_form {
+ width: 590px;
+}
+
+#openid_form legend {
+ font-weight: bold;
+}
+
+#openid_choice {
+ display: none;
+}
+
+#openid_input_area {
+ clear: both;
+ padding: 10px;
+}
+
+#openid_btns, #openid_btns br {
+ clear: both;
+}
+
+#openid_highlight {
+ padding: 3px;
+ background-color: #FFFCC9;
+ float: left;
+}
+
+.openid_large_btn {
+ width: 100px;
+ height: 60px;
+/* fix for IE 6 only: http://en.wikipedia.org/wiki/CSS_filter#Underscore_hack */
+ _width: 104px;
+ _height: 64px;
+
+ border: 2px solid #DDD;
+ border-right: 2px solid #ccc;
+ border-bottom: 2px solid #ccc;
+ margin: 3px;
+ float: left;
+ border-radius: 5px;
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+ box-shadow: 2px 2px 4px #ddd;
+ -moz-box-shadow: 2px 2px 4px #ddd;
+ -webkit-box-shadow: 2px 2px 4px #ddd;
+}
+
+.openid_large_btn:hover {
+ margin: 4px 0 0 6px;
+ border: 2px solid #999;
+ box-shadow: none;
+ -moz-box-shadow: none;
+ -webkit-box-shadow: none;
+}
+
+.openid_small_btn {
+ width: 24px;
+ height: 24px;
+/* fix for IE 6 only: http://en.wikipedia.org/wiki/CSS_filter#Underscore_hack */
+ _width: 28px;
+ _height: 28px;
+
+ border: 2px solid #DDD;
+ border-right: 2px solid #ccc;
+ border-bottom: 2px solid #ccc;
+ margin: 3px;
+ float: left;
+ border-radius: 5px;
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+ box-shadow: 2px 2px 4px #ddd;
+ -moz-box-shadow: 2px 2px 4px #ddd;
+ -webkit-box-shadow: 2px 2px 4px #ddd;
+}
+
+.openid_small_btn:hover {
+ margin: 4px 0 0 6px;
+ border: 2px solid #999;
+ box-shadow: none;
+ -moz-box-shadow: none;
+ -webkit-box-shadow: none;
+}
+
+a.openid_large_btn:focus {
+ outline: none;
+}
+
+a.openid_large_btn:focus {
+ -moz-outline-style: none;
+}
+
+.openid_selected {
+ border: 4px solid #DDD;
+}
View
69 samples/ruby-login-server/public/css/openid.css
@@ -0,0 +1,69 @@
+/*
+ Simple OpenID Plugin
+ http://code.google.com/p/openid-selector/
+
+ This code is licensed under the New BSD License.
+*/
+
+#openid_form {
+ width: 580px;
+}
+
+#openid_form legend {
+ font-weight: bold;
+}
+
+#openid_choice {
+ display: none;
+}
+
+#openid_input_area {
+ clear: both;
+ padding: 10px;
+}
+
+#openid_btns, #openid_btns br {
+ clear: both;
+}
+
+#openid_highlight {
+ padding: 3px;
+ background-color: #FFFCC9;
+ float: left;
+}
+
+.openid_large_btn {
+ width: 100px;
+ height: 60px;
+/* fix for IE 6 only: http://en.wikipedia.org/wiki/CSS_filter#Underscore_hack */
+ _width: 102px;
+ _height: 62px;
+
+ border: 1px solid #DDD;
+ margin: 3px;
+ float: left;
+}
+
+.openid_small_btn {
+ width: 24px;
+ height: 24px;
+/* fix for IE 6 only: http://en.wikipedia.org/wiki/CSS_filter#Underscore_hack */
+ _width: 26px;
+ _height: 26px;
+
+ border: 1px solid #DDD;
+ margin: 3px;
+ float: left;
+}
+
+a.openid_large_btn:focus {
+ outline: none;
+}
+
+a.openid_large_btn:focus {
+ -moz-outline-style: none;
+}
+
+.openid_selected {
+ border: 4px solid #DDD;
+}
View
BIN samples/ruby-login-server/public/images.large/aol.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN samples/ruby-login-server/public/images.large/facebook.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN samples/ruby-login-server/public/images.large/google.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN samples/ruby-login-server/public/images.large/mailru.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN samples/ruby-login-server/public/images.large/myopenid.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN samples/ruby-login-server/public/images.large/openid.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN samples/ruby-login-server/public/images.large/rambler.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN samples/ruby-login-server/public/images.large/verisign.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN samples/ruby-login-server/public/images.large/vkontakte.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN samples/ruby-login-server/public/images.large/yahoo.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN samples/ruby-login-server/public/images.large/yandex.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN samples/ruby-login-server/public/images.small/aol.ico
Binary file not shown.
View
BIN samples/ruby-login-server/public/images.small/aol.ico.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN samples/ruby-login-server/public/images.small/aol.ico.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN samples/ruby-login-server/public/images.small/blogger.ico
Binary file not shown.
View
BIN samples/ruby-login-server/public/images.small/blogger.ico.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN samples/ruby-login-server/public/images.small/blogger.ico.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN samples/ruby-login-server/public/images.small/claimid.ico
Binary file not shown.
View
BIN samples/ruby-login-server/public/images.small/claimid.ico.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN samples/ruby-login-server/public/images.small/claimid.ico.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN samples/ruby-login-server/public/images.small/clickpass.ico
Binary file not shown.
View
BIN samples/ruby-login-server/public/images.small/clickpass.ico.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN samples/ruby-login-server/public/images.small/clickpass.ico.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN samples/ruby-login-server/public/images.small/facebook.ico
Binary file not shown.
View
BIN samples/ruby-login-server/public/images.small/facebook.ico.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN samples/ruby-login-server/public/images.small/facebook.ico.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN samples/ruby-login-server/public/images.small/flickr.ico
Binary file not shown.
View
BIN samples/ruby-login-server/public/images.small/flickr.ico.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN samples/ruby-login-server/public/images.small/flickr.ico.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN samples/ruby-login-server/public/images.small/google.ico
Binary file not shown.
View
BIN samples/ruby-login-server/public/images.small/google.ico.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN samples/ruby-login-server/public/images.small/google.ico.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN samples/ruby-login-server/public/images.small/google_profile.ico
Binary file not shown.
View
BIN samples/ruby-login-server/public/images.small/google_profile.ico.gif
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/google_profile.ico.png
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/launchpad.ico
Binary file not shown.
View
BIN samples/ruby-login-server/public/images.small/launchpad.ico.gif
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/launchpad.ico.png
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/linkedin.ico
Binary file not shown.
View
BIN samples/ruby-login-server/public/images.small/linkedin.ico.gif
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/linkedin.ico.png
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/livejournal.ico
Binary file not shown.
View
BIN samples/ruby-login-server/public/images.small/livejournal.ico.gif
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/livejournal.ico.png
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/mailru.ico
Binary file not shown.
View
BIN samples/ruby-login-server/public/images.small/mailru.ico.gif
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/mailru.ico.png
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/myopenid.ico
Binary file not shown.
View
BIN samples/ruby-login-server/public/images.small/myopenid.ico.gif
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/myopenid.ico.png
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/openid.ico
Binary file not shown.
View
BIN samples/ruby-login-server/public/images.small/openid.ico.gif
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/openid.ico.png
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/rambler.ico
Binary file not shown.
View
BIN samples/ruby-login-server/public/images.small/rambler.ico.gif
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/rambler.ico.png
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/technorati.ico
Binary file not shown.
View
BIN samples/ruby-login-server/public/images.small/technorati.ico.gif
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/technorati.ico.png
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/twitter.ico
Binary file not shown.
View
BIN samples/ruby-login-server/public/images.small/twitter.ico.gif
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/twitter.ico.png
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/verisign.ico
Binary file not shown.
View
BIN samples/ruby-login-server/public/images.small/verisign.ico.gif
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/verisign.ico.png
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/vidoop.ico
Binary file not shown.
View
BIN samples/ruby-login-server/public/images.small/vidoop.ico.gif
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/vidoop.ico.png
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/vkontakte.ico
Binary file not shown.
View
BIN samples/ruby-login-server/public/images.small/vkontakte.ico.gif
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/vkontakte.ico.png
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/winliveid.ico
Binary file not shown.
View
BIN samples/ruby-login-server/public/images.small/winliveid.ico.gif
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/winliveid.ico.png
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/wordpress.ico
Binary file not shown.
View
BIN samples/ruby-login-server/public/images.small/wordpress.ico.gif
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/wordpress.ico.png
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/yahoo.ico
Binary file not shown.
View
BIN samples/ruby-login-server/public/images.small/yahoo.ico.gif
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/yahoo.ico.png
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/yandex.ico
Binary file not shown.
View
BIN samples/ruby-login-server/public/images.small/yandex.ico.gif
Diff not rendered.
View
BIN samples/ruby-login-server/public/images.small/yandex.ico.png
Diff not rendered.
View
BIN samples/ruby-login-server/public/images/openid-inputicon.gif
Diff not rendered.
View
BIN samples/ruby-login-server/public/images/openid-providers-en.png
Diff not rendered.
View
BIN samples/ruby-login-server/public/images/openid-providers-ru.png
Diff not rendered.
View
32 samples/ruby-login-server/public/js/jquery-1.2.6.min.js
@@ -0,0 +1,32 @@
+/*
+ * jQuery 1.2.6 - New Wave Javascript
+ *
+ * Copyright (c) 2008 John Resig (jquery.com)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * $Date: 2008-05-24 14:22:17 -0400 (Sat, 24 May 2008) $
+ * $Rev: 5685 $
+ */
+(function(){var _jQuery=window.jQuery,_$=window.$;var jQuery=window.jQuery=window.$=function(selector,context){return new jQuery.fn.init(selector,context);};var quickExpr=/^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/,isSimple=/^.[^:#\[\.]*$/,undefined;jQuery.fn=jQuery.prototype={init:function(selector,context){selector=selector||document;if(selector.nodeType){this[0]=selector;this.length=1;return this;}if(typeof selector=="string"){var match=quickExpr.exec(selector);if(match&&(match[1]||!context)){if(match[1])selector=jQuery.clean([match[1]],context);else{var elem=document.getElementById(match[3]);if(elem){if(elem.id!=match[3])return jQuery().find(selector);return jQuery(elem);}selector=[];}}else
+return jQuery(context).find(selector);}else if(jQuery.isFunction(selector))return jQuery(document)[jQuery.fn.ready?"ready":"load"](selector);return this.setArray(jQuery.makeArray(selector));},jquery:"1.2.6",size:function(){return this.length;},length:0,get:function(num){return num==undefined?jQuery.makeArray(this):this[num];},pushStack:function(elems){var ret=jQuery(elems);ret.prevObject=this;return ret;},setArray:function(elems){this.length=0;Array.prototype.push.apply(this,elems);return this;},each:function(callback,args){return jQuery.each(this,callback,args);},index:function(elem){var ret=-1;return jQuery.inArray(elem&&elem.jquery?elem[0]:elem,this);},attr:function(name,value,type){var options=name;if(name.constructor==String)if(value===undefined)return this[0]&&jQuery[type||"attr"](this[0],name);else{options={};options[name]=value;}return this.each(function(i){for(name in options)jQuery.attr(type?this.style:this,name,jQuery.prop(this,options[name],type,i,name));});},css:function(key,value){if((key=='width'||key=='height')&&parseFloat(value)<0)value=undefined;return this.attr(key,value,"curCSS");},text:function(text){if(typeof text!="object"&&text!=null)return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(text));var ret="";jQuery.each(text||this,function(){jQuery.each(this.childNodes,function(){if(this.nodeType!=8)ret+=this.nodeType!=1?this.nodeValue:jQuery.fn.text([this]);});});return ret;},wrapAll:function(html){if(this[0])jQuery(html,this[0].ownerDocument).clone().insertBefore(this[0]).map(function(){var elem=this;while(elem.firstChild)elem=elem.firstChild;return elem;}).append(this);return this;},wrapInner:function(html){return this.each(function(){jQuery(this).contents().wrapAll(html);});},wrap:function(html){return this.each(function(){jQuery(this).wrapAll(html);});},append:function(){return this.domManip(arguments,true,false,function(elem){if(this.nodeType==1)this.appendChild(elem);});},prepend:function(){return this.domManip(arguments,true,true,function(elem){if(this.nodeType==1)this.insertBefore(elem,this.firstChild);});},before:function(){return this.domManip(arguments,false,false,function(elem){this.parentNode.insertBefore(elem,this);});},after:function(){return this.domManip(arguments,false,true,function(elem){this.parentNode.insertBefore(elem,this.nextSibling);});},end:function(){return this.prevObject||jQuery([]);},find:function(selector){var elems=jQuery.map(this,function(elem){return jQuery.find(selector,elem);});return this.pushStack(/[^+>] [^+>]/.test(selector)||selector.indexOf("..")>-1?jQuery.unique(elems):elems);},clone:function(events){var ret=this.map(function(){if(jQuery.browser.msie&&!jQuery.isXMLDoc(this)){var clone=this.cloneNode(true),container=document.createElement("div");container.appendChild(clone);return jQuery.clean([container.innerHTML])[0];}else
+return this.cloneNode(true);});var clone=ret.find("*").andSelf().each(function(){if(this[expando]!=undefined)this[expando]=null;});if(events===true)this.find("*").andSelf().each(function(i){if(this.nodeType==3)return;var events=jQuery.data(this,"events");for(var type in events)for(var handler in events[type])jQuery.event.add(clone[i],type,events[type][handler],events[type][handler].data);});return ret;},filter:function(selector){return this.pushStack(jQuery.isFunction(selector)&&jQuery.grep(this,function(elem,i){return selector.call(elem,i);})||jQuery.multiFilter(selector,this));},not:function(selector){if(selector.constructor==String)if(isSimple.test(selector))return this.pushStack(jQuery.multiFilter(selector,this,true));else
+selector=jQuery.multiFilter(selector,this);var isArrayLike=selector.length&&selector[selector.length-1]!==undefined&&!selector.nodeType;return this.filter(function(){return isArrayLike?jQuery.inArray(this,selector)<0:this!=selector;});},add:function(selector){return this.pushStack(jQuery.unique(jQuery.merge(this.get(),typeof selector=='string'?jQuery(selector):jQuery.makeArray(selector))));},is:function(selector){return!!selector&&jQuery.multiFilter(selector,this).length>0;},hasClass:function(selector){return this.is("."+selector);},val:function(value){if(value==undefined){if(this.length){var elem=this[0];if(jQuery.nodeName(elem,"select")){var index=elem.selectedIndex,values=[],options=elem.options,one=elem.type=="select-one";if(index<0)return null;for(var i=one?index:0,max=one?index+1:options.length;i<max;i++){var option=options[i];if(option.selected){value=jQuery.browser.msie&&!option.attributes.value.specified?option.text:option.value;if(one)return value;values.push(value);}}return values;}else
+return(this[0].value||"").replace(/\r/g,"");}return undefined;}if(value.constructor==Number)value+='';return this.each(function(){if(this.nodeType!=1)return;if(value.constructor==Array&&/radio|checkbox/.test(this.type))this.checked=(jQuery.inArray(this.value,value)>=0||jQuery.inArray(this.name,value)>=0);else if(jQuery.nodeName(this,"select")){var values=jQuery.makeArray(value);jQuery("option",this).each(function(){this.selected=(jQuery.inArray(this.value,values)>=0||jQuery.inArray(this.text,values)>=0);});if(!values.length)this.selectedIndex=-1;}else
+this.value=value;});},html:function(value){return value==undefined?(this[0]?this[0].innerHTML:null):this.empty().append(value);},replaceWith:function(value){return this.after(value).remove();},eq:function(i){return this.slice(i,i+1);},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments));},map:function(callback){return this.pushStack(jQuery.map(this,function(elem,i){return callback.call(elem,i,elem);}));},andSelf:function(){return this.add(this.prevObject);},data:function(key,value){var parts=key.split(".");parts[1]=parts[1]?"."+parts[1]:"";if(value===undefined){var data=this.triggerHandler("getData"+parts[1]+"!",[parts[0]]);if(data===undefined&&this.length)data=jQuery.data(this[0],key);return data===undefined&&parts[1]?this.data(parts[0]):data;}else
+return this.trigger("setData"+parts[1]+"!",[parts[0],value]).each(function(){jQuery.data(this,key,value);});},removeData:function(key){return this.each(function(){jQuery.removeData(this,key);});},domManip:function(args,table,reverse,callback){var clone=this.length>1,elems;return this.each(function(){if(!elems){elems=jQuery.clean(args,this.ownerDocument);if(reverse)elems.reverse();}var obj=this;if(table&&jQuery.nodeName(this,"table")&&jQuery.nodeName(elems[0],"tr"))obj=this.getElementsByTagName("tbody")[0]||this.appendChild(this.ownerDocument.createElement("tbody"));var scripts=jQuery([]);jQuery.each(elems,function(){var elem=clone?jQuery(this).clone(true)[0]:this;if(jQuery.nodeName(elem,"script"))scripts=scripts.add(elem);else{if(elem.nodeType==1)scripts=scripts.add(jQuery("script",elem).remove());callback.call(obj,elem);}});scripts.each(evalScript);});}};jQuery.fn.init.prototype=jQuery.fn;function evalScript(i,elem){if(elem.src)jQuery.ajax({url:elem.src,async:false,dataType:"script"});else
+jQuery.globalEval(elem.text||elem.textContent||elem.innerHTML||"");if(elem.parentNode)elem.parentNode.removeChild(elem);}function now(){return+new Date;}jQuery.extend=jQuery.fn.extend=function(){var target=arguments[0]||{},i=1,length=arguments.length,deep=false,options;if(target.constructor==Boolean){deep=target;target=arguments[1]||{};i=2;}if(typeof target!="object"&&typeof target!="function")target={};if(length==i){target=this;--i;}for(;i<length;i++)if((options=arguments[i])!=null)for(var name in options){var src=target[name],copy=options[name];if(target===copy)continue;if(deep&&copy&&typeof copy=="object"&&!copy.nodeType)target[name]=jQuery.extend(deep,src||(copy.length!=null?[]:{}),copy);else if(copy!==undefined)target[name]=copy;}return target;};var expando="jQuery"+now(),uuid=0,windowData={},exclude=/z-?index|font-?weight|opacity|zoom|line-?height/i,defaultView=document.defaultView||{};jQuery.extend({noConflict:function(deep){window.$=_$;if(deep)window.jQuery=_jQuery;return jQuery;},isFunction:function(fn){return!!fn&&typeof fn!="string"&&!fn.nodeName&&fn.constructor!=Array&&/^[\s[]?function/.test(fn+"");},isXMLDoc:function(elem){return elem.documentElement&&!elem.body||elem.tagName&&elem.ownerDocument&&!elem.ownerDocument.body;},globalEval:function(data){data=jQuery.trim(data);if(data){var head=document.getElementsByTagName("head")[0]||document.documentElement,script=document.createElement("script");script.type="text/javascript";if(jQuery.browser.msie)script.text=data;else
+script.appendChild(document.createTextNode(data));head.insertBefore(script,head.firstChild);head.removeChild(script);}},nodeName:function(elem,name){return elem.nodeName&&elem.nodeName.toUpperCase()==name.toUpperCase();},cache:{},data:function(elem,name,data){elem=elem==window?windowData:elem;var id=elem[expando];if(!id)id=elem[expando]=++uuid;if(name&&!jQuery.cache[id])jQuery.cache[id]={};if(data!==undefined)jQuery.cache[id][name]=data;return name?jQuery.cache[id][name]:id;},removeData:function(elem,name){elem=elem==window?windowData:elem;var id=elem[expando];if(name){if(jQuery.cache[id]){delete jQuery.cache[id][name];name="";for(name in jQuery.cache[id])break;if(!name)jQuery.removeData(elem);}}else{try{delete elem[expando];}catch(e){if(elem.removeAttribute)elem.removeAttribute(expando);}delete jQuery.cache[id];}},each:function(object,callback,args){var name,i=0,length=object.length;if(args){if(length==undefined){for(name in object)if(callback.apply(object[name],args)===false)break;}else
+for(;i<length;)if(callback.apply(object[i++],args)===false)break;}else{if(length==undefined){for(name in object)if(callback.call(object[name],name,object[name])===false)break;}else
+for(var value=object[0];i<length&&callback.call(value,i,value)!==false;value=object[++i]){}}return object;},prop:function(elem,value,type,i,name){if(jQuery.isFunction(value))value=value.call(elem,i);return value&&value.constructor==Number&&type=="curCSS"&&!exclude.test(name)?value+"px":value;},className:{add:function(elem,classNames){jQuery.each((classNames||"").split(/\s+/),function(i,className){if(elem.nodeType==1&&!jQuery.className.has(elem.className,className))elem.className+=(elem.className?" ":"")+className;});},remove:function(elem,classNames){if(elem.nodeType==1)elem.className=classNames!=undefined?jQuery.grep(elem.className.split(/\s+/),function(className){return!jQuery.className.has(classNames,className);}).join(" "):"";},has:function(elem,className){return jQuery.inArray(className,(elem.className||elem).toString().split(/\s+/))>-1;}},swap:function(elem,options,callback){var old={};for(var name in options){old[name]=elem.style[name];elem.style[name]=options[name];}callback.call(elem);for(var name in options)elem.style[name]=old[name];},css:function(elem,name,force){if(name=="width"||name=="height"){var val,props={position:"absolute",visibility:"hidden",display:"block"},which=name=="width"?["Left","Right"]:["Top","Bottom"];function getWH(){val=name=="width"?elem.offsetWidth:elem.offsetHeight;var padding=0,border=0;jQuery.each(which,function(){padding+=parseFloat(jQuery.curCSS(elem,"padding"+this,true))||0;border+=parseFloat(jQuery.curCSS(elem,"border"+this+"Width",true))||0;});val-=Math.round(padding+border);}if(jQuery(elem).is(":visible"))getWH();else
+jQuery.swap(elem,props,getWH);return Math.max(0,val);}return jQuery.curCSS(elem,name,force);},curCSS:function(elem,name,force){var ret,style=elem.style;function color(elem){if(!jQuery.browser.safari)return false;var ret=defaultView.getComputedStyle(elem,null);return!ret||ret.getPropertyValue("color")=="";}if(name=="opacity"&&jQuery.browser.msie){ret=jQuery.attr(style,"opacity");return ret==""?"1":ret;}if(jQuery.browser.opera&&name=="display"){var save=style.outline;style.outline="0 solid black";style.outline=save;}if(name.match(/float/i))name=styleFloat;if(!force&&style&&style[name])ret=style[name];else if(defaultView.getComputedStyle){if(name.match(/float/i))name="float";name=name.replace(/([A-Z])/g,"-$1").toLowerCase();var computedStyle=defaultView.getComputedStyle(elem,null);if(computedStyle&&!color(elem))ret=computedStyle.getPropertyValue(name);else{var swap=[],stack=[],a=elem,i=0;for(;a&&color(a);a=a.parentNode)stack.unshift(a);for(;i<stack.length;i++)if(color(stack[i])){swap[i]=stack[i].style.display;stack[i].style.display="block";}ret=name=="display"&&swap[stack.length-1]!=null?"none":(computedStyle&&computedStyle.getPropertyValue(name))||"";for(i=0;i<swap.length;i++)if(swap[i]!=null)stack[i].style.display=swap[i];}if(name=="opacity"&&ret=="")ret="1";}else if(elem.currentStyle){var camelCase=name.replace(/\-(\w)/g,function(all,letter){return letter.toUpperCase();});ret=elem.currentStyle[name]||elem.currentStyle[camelCase];if(!/^\d+(px)?$/i.test(ret)&&/^\d/.test(ret)){var left=style.left,rsLeft=elem.runtimeStyle.left;elem.runtimeStyle.left=elem.currentStyle.left;style.left=ret||0;ret=style.pixelLeft+"px";style.left=left;elem.runtimeStyle.left=rsLeft;}}return ret;},clean:function(elems,context){var ret=[];context=context||document;if(typeof context.createElement=='undefined')context=context.ownerDocument||context[0]&&context[0].ownerDocument||document;jQuery.each(elems,function(i,elem){if(!elem)return;if(elem.constructor==Number)elem+='';if(typeof elem=="string"){elem=elem.replace(/(<(\w+)[^>]*?)\/>/g,function(all,front,tag){return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?all:front+"></"+tag+">";});var tags=jQuery.trim(elem).toLowerCase(),div=context.createElement("div");var wrap=!tags.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!tags.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||tags.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!tags.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!tags.indexOf("<td")||!tags.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!tags.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||jQuery.browser.msie&&[1,"div<div>","</div>"]||[0,"",""];div.innerHTML=wrap[1]+elem+wrap[2];while(wrap[0]--)div=div.lastChild;if(jQuery.browser.msie){var tbody=!tags.indexOf("<table")&&tags.indexOf("<tbody")<0?div.firstChild&&div.firstChild.childNodes:wrap[1]=="<table>"&&tags.indexOf("<tbody")<0?div.childNodes:[];for(var j=tbody.length-1;j>=0;--j)if(jQuery.nodeName(tbody[j],"tbody")&&!tbody[j].childNodes.length)tbody[j].parentNode.removeChild(tbody[j]);if(/^\s/.test(elem))div.insertBefore(context.createTextNode(elem.match(/^\s*/)[0]),div.firstChild);}elem=jQuery.makeArray(div.childNodes);}if(elem.length===0&&(!jQuery.nodeName(elem,"form")&&!jQuery.nodeName(elem,"select")))return;if(elem[0]==undefined||jQuery.nodeName(elem,"form")||elem.options)ret.push(elem);else
+ret=jQuery.merge(ret,elem);});return ret;},attr:function(elem,name,value){if(!elem||elem.nodeType==3||elem.nodeType==8)return undefined;var notxml=!jQuery.isXMLDoc(elem),set=value!==undefined,msie=jQuery.browser.msie;name=notxml&&jQuery.props[name]||name;if(elem.tagName){var special=/href|src|style/.test(name);if(name=="selected"&&jQuery.browser.safari)elem.parentNode.selectedIndex;if(name in elem&&notxml&&!special){if(set){if(name=="type"&&jQuery.nodeName(elem,"input")&&elem.parentNode)throw"type property can't be changed";elem[name]=value;}if(jQuery.nodeName(elem,"form")&&elem.getAttributeNode(name))return elem.getAttributeNode(name).nodeValue;return elem[name];}if(msie&&notxml&&name=="style")return jQuery.attr(elem.style,"cssText",value);if(set)elem.setAttribute(name,""+value);var attr=msie&&notxml&&special?elem.getAttribute(name,2):elem.getAttribute(name);return attr===null?undefined:attr;}if(msie&&name=="opacity"){if(set){elem.zoom=1;elem.filter=(elem.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(value)+''=="NaN"?"":"alpha(opacity="+value*100+")");}return elem.filter&&elem.filter.indexOf("opacity=")>=0?(parseFloat(elem.filter.match(/opacity=([^)]*)/)[1])/100)+'':"";}name=name.replace(/-([a-z])/ig,function(all,letter){return letter.toUpperCase();});if(set)elem[name]=value;return elem[name];},trim:function(text){return(text||"").replace(/^\s+|\s+$/g,"");},makeArray:function(array){var ret=[];if(array!=null){var i=array.length;if(i==null||array.split||array.setInterval||array.call)ret[0]=array;else
+while(i)ret[--i]=array[i];}return ret;},inArray:function(elem,array){for(var i=0,length=array.length;i<length;i++)if(array[i]===elem)return i;return-1;},merge:function(first,second){var i=0,elem,pos=first.length;if(jQuery.browser.msie){while(elem=second[i++])if(elem.nodeType!=8)first[pos++]=elem;}else
+while(elem=second[i++])first[pos++]=elem;return first;},unique:function(array){var ret=[],done={};try{for(var i=0,length=array.length;i<length;i++){var id=jQuery.data(array[i]);if(!done[id]){done[id]=true;ret.push(array[i]);}}}catch(e){ret=array;}return ret;},grep:function(elems,callback,inv){var ret=[];for(var i=0,length=elems.length;i<length;i++)if(!inv!=!callback(elems[i],i))ret.push(elems[i]);return ret;},map:function(elems,callback){var ret=[];for(var i=0,length=elems.length;i<length;i++){var value=callback(elems[i],i);if(value!=null)ret[ret.length]=value;}return ret.concat.apply([],ret);}});var userAgent=navigator.userAgent.toLowerCase();jQuery.browser={version:(userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[])[1],safari:/webkit/.test(userAgent),opera:/opera/.test(userAgent),msie:/msie/.test(userAgent)&&!/opera/.test(userAgent),mozilla:/mozilla/.test(userAgent)&&!/(compatible|webkit)/.test(userAgent)};var styleFloat=jQuery.browser.msie?"styleFloat":"cssFloat";jQuery.extend({boxModel:!jQuery.browser.msie||document.compatMode=="CSS1Compat",props:{"for":"htmlFor","class":"className","float":styleFloat,cssFloat:styleFloat,styleFloat:styleFloat,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing"}});jQuery.each({parent:function(elem){return elem.parentNode;},parents:function(elem){return jQuery.dir(elem,"parentNode");},next:function(elem){return jQuery.nth(elem,2,"nextSibling");},prev:function(elem){return jQuery.nth(elem,2,"previousSibling");},nextAll:function(elem){return jQuery.dir(elem,"nextSibling");},prevAll:function(elem){return jQuery.dir(elem,"previousSibling");},siblings:function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);},children:function(elem){return jQuery.sibling(elem.firstChild);},contents:function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);}},function(name,fn){jQuery.fn[name]=function(selector){var ret=jQuery.map(this,fn);if(selector&&typeof selector=="string")ret=jQuery.multiFilter(selector,ret);return this.pushStack(jQuery.unique(ret));};});jQuery.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(name,original){jQuery.fn[name]=function(){var args=arguments;return this.each(function(){for(var i=0,length=args.length;i<length;i++)jQuery(args[i])[original](this);});};});jQuery.each({removeAttr:function(name){jQuery.attr(this,name,"");if(this.nodeType==1)this.removeAttribute(name);},addClass:function(classNames){jQuery.className.add(this,classNames);},removeClass:function(classNames){jQuery.className.remove(this,classNames);},toggleClass:function(classNames){jQuery.className[jQuery.className.has(this,classNames)?"remove":"add"](this,classNames);},remove:function(selector){if(!selector||jQuery.filter(selector,[this]).r.length){jQuery("*",this).add(this).each(function(){jQuery.event.remove(this);jQuery.removeData(this);});if(this.parentNode)this.parentNode.removeChild(this);}},empty:function(){jQuery(">*",this).remove();while(this.firstChild)this.removeChild(this.firstChild);}},function(name,fn){jQuery.fn[name]=function(){return this.each(fn,arguments);};});jQuery.each(["Height","Width"],function(i,name){var type=name.toLowerCase();jQuery.fn[type]=function(size){return this[0]==window?jQuery.browser.opera&&document.body["client"+name]||jQuery.browser.safari&&window["inner"+name]||document.compatMode=="CSS1Compat"&&document.documentElement["client"+name]||document.body["client"+name]:this[0]==document?Math.max(Math.max(document.body["scroll"+name],document.documentElement["scroll"+name]),Math.max(document.body["offset"+name],document.documentElement["offset"+name])):size==undefined?(this.length?jQuery.css(this[0],type):null):this.css(type,size.constructor==String?size:size+"px");};});function num(elem,prop){return elem[0]&&parseInt(jQuery.curCSS(elem[0],prop,true),10)||0;}var chars=jQuery.browser.safari&&parseInt(jQuery.browser.version)<417?"(?:[\\w*_-]|\\\\.)":"(?:[\\w\u0128-\uFFFF*_-]|\\\\.)",quickChild=new RegExp("^>\\s*("+chars+"+)"),quickID=new RegExp("^("+chars+"+)(#)("+chars+"+)"),quickClass=new RegExp("^([#.]?)("+chars+"*)");jQuery.extend({expr:{"":function(a,i,m){return m[2]=="*"||jQuery.nodeName(a,m[2]);},"#":function(a,i,m){return a.getAttribute("id")==m[2];},":":{lt:function(a,i,m){return i<m[3]-0;},gt:function(a,i,m){return i>m[3]-0;},nth:function(a,i,m){return m[3]-0==i;},eq:function(a,i,m){return m[3]-0==i;},first:function(a,i){return i==0;},last:function(a,i,m,r){return i==r.length-1;},even:function(a,i){return i%2==0;},odd:function(a,i){return i%2;},"first-child":function(a){return a.parentNode.getElementsByTagName("*")[0]==a;},"last-child":function(a){return jQuery.nth(a.parentNode.lastChild,1,"previousSibling")==a;},"only-child":function(a){return!jQuery.nth(a.parentNode.lastChild,2,"previousSibling");},parent:function(a){return a.firstChild;},empty:function(a){return!a.firstChild;},contains:function(a,i,m){return(a.textContent||a.innerText||jQuery(a).text()||"").indexOf(m[3])>=0;},visible:function(a){return"hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden";},hidden:function(a){return"hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden";},enabled:function(a){return!a.disabled;},disabled:function(a){return a.disabled;},checked:function(a){return a.checked;},selected:function(a){return a.selected||jQuery.attr(a,"selected");},text:function(a){return"text"==a.type;},radio:function(a){return"radio"==a.type;},checkbox:function(a){return"checkbox"==a.type;},file:function(a){return"file"==a.type;},password:function(a){return"password"==a.type;},submit:function(a){return"submit"==a.type;},image:function(a){return"image"==a.type;},reset:function(a){return"reset"==a.type;},button:function(a){return"button"==a.type||jQuery.nodeName(a,"button");},input:function(a){return/input|select|textarea|button/i.test(a.nodeName);},has:function(a,i,m){return jQuery.find(m[3],a).length;},header:function(a){return/h\d/i.test(a.nodeName);},animated:function(a){return jQuery.grep(jQuery.timers,function(fn){return a==fn.elem;}).length;}}},parse:[/^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/,/^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/,new RegExp("^([:.#]*)("+chars+"+)")],multiFilter:function(expr,elems,not){var old,cur=[];while(expr&&expr!=old){old=expr;var f=jQuery.filter(expr,elems,not);expr=f.t.replace(/^\s*,\s*/,"");cur=not?elems=f.r:jQuery.merge(cur,f.r);}return cur;},find:function(t,context){if(typeof t!="string")return[t];if(context&&context.nodeType!=1&&context.nodeType!=9)return[];context=context||document;var ret=[context],done=[],last,nodeName;while(t&&last!=t){var r=[];last=t;t=jQuery.trim(t);var foundToken=false,re=quickChild,m=re.exec(t);if(m){nodeName=m[1].toUpperCase();for(var i=0;ret[i];i++)for(var c=ret[i].firstChild;c;c=c.nextSibling)if(c.nodeType==1&&(nodeName=="*"||c.nodeName.toUpperCase()==nodeName))r.push(c);ret=r;t=t.replace(re,"");if(t.indexOf(" ")==0)continue;foundToken=true;}else{re=/^([>+~])\s*(\w*)/i;if((m=re.exec(t))!=null){r=[];var merge={};nodeName=m[2].toUpperCase();m=m[1];for(var j=0,rl=ret.length;j<rl;j++){var n=m=="~"||m=="+"?ret[j].nextSibling:ret[j].firstChild;for(;n;n=n.nextSibling)if(n.nodeType==1){var id=jQuery.data(n);if(m=="~"&&merge[id])break;if(!nodeName||n.nodeName.toUpperCase()==nodeName){if(m=="~")merge[id]=true;r.push(n);}if(m=="+")break;}}ret=r;t=jQuery.trim(t.replace(re,""));foundToken=true;}}if(t&&!foundToken){if(!t.indexOf(",")){if(context==ret[0])ret.shift();done=jQuery.merge(done,ret);r=ret=[context];t=" "+t.substr(1,t.length);}else{var re2=quickID;var m=re2.exec(t);if(m){m=[0,m[2],m[3],m[1]];}else{re2=quickClass;m=re2.exec(t);}m[2]=m[2].replace(/\\/g,"");var elem=ret[ret.length-1];if(m[1]=="#"&&elem&&elem.getElementById&&!jQuery.isXMLDoc(elem)){var oid=elem.getElementById(m[2]);if((jQuery.browser.msie||jQuery.browser.opera)&&oid&&typeof oid.id=="string"&&oid.id!=m[2])oid=jQuery('[@id="'+m[2]+'"]',elem)[0];ret=r=oid&&(!m[3]||jQuery.nodeName(oid,m[3]))?[oid]:[];}else{for(var i=0;ret[i];i++){var tag=m[1]=="#"&&m[3]?m[3]:m[1]!=""||m[0]==""?"*":m[2];if(tag=="*"&&ret[i].nodeName.toLowerCase()=="object")tag="param";r=jQuery.merge(r,ret[i].getElementsByTagName(tag));}if(m[1]==".")r=jQuery.classFilter(r,m[2]);if(m[1]=="#"){var tmp=[];for(var i=0;r[i];i++)if(r[i].getAttribute("id")==m[2]){tmp=[r[i]];break;}r=tmp;}ret=r;}t=t.replace(re2,"");}}if(t){var val=jQuery.filter(t,r);ret=r=val.r;t=jQuery.trim(val.t);}}if(t)ret=[];if(ret&&context==ret[0])ret.shift();done=jQuery.merge(done,ret);return done;},classFilter:function(r,m,not){m=" "+m+" ";var tmp=[];for(var i=0;r[i];i++){var pass=(" "+r[i].className+" ").indexOf(m)>=0;if(!not&&pass||not&&!pass)tmp.push(r[i]);}return tmp;},filter:function(t,r,not){var last;while(t&&t!=last){last=t;var p=jQuery.parse,m;for(var i=0;p[i];i++){m=p[i].exec(t);if(m){t=t.substring(m[0].length);m[2]=m[2].replace(/\\/g,"");break;}}if(!m)break;if(m[1]==":"&&m[2]=="not")r=isSimple.test(m[3])?jQuery.filter(m[3],r,true).r:jQuery(r).not(m[3]);else if(m[1]==".")r=jQuery.classFilter(r,m[2],not);else if(m[1]=="["){var tmp=[],type=m[3];for(var i=0,rl=r.length;i<rl;i++){var a=r[i],z=a[jQuery.props[m[2]]||m[2]];if(z==null||/href|src|selected/.test(m[2]))z=jQuery.attr(a,m[2])||'';if((type==""&&!!z||type=="="&&z==m[5]||type=="!="&&z!=m[5]||type=="^="&&z&&!z.indexOf(m[5])||type=="$="&&z.substr(z.length-m[5].length)==m[5]||(type=="*="||type=="~=")&&z.indexOf(m[5])>=0)^not)tmp.push(a);}r=tmp;}else if(m[1]==":"&&m[2]=="nth-child"){var merge={},tmp=[],test=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(m[3]=="even"&&"2n"||m[3]=="odd"&&"2n+1"||!/\D/.test(m[3])&&"0n+"+m[3]||m[3]),first=(test[1]+(test[2]||1))-0,last=test[3]-0;for(var i=0,rl=r.length;i<rl;i++){var node=r[i],parentNode=node.parentNode,id=jQuery.data(parentNode);if(!merge[id]){var c=1;for(var n=parentNode.firstChild;n;n=n.nextSibling)if(n.nodeType==1)n.nodeIndex=c++;merge[id]=true;}var add=false;if(first==0){if(node.nodeIndex==last)add=true;}else if((node.nodeIndex-last)%first==0&&(node.nodeIndex-last)/first>=0)add=true;if(add^not)tmp.push(node);}r=tmp;}else{var fn=jQuery.expr[m[1]];if(typeof fn=="object")fn=fn[m[2]];if(typeof fn=="string")fn=eval("false||function(a,i){return "+fn+";}");r=jQuery.grep(r,function(elem,i){return fn(elem,i,m,r);},not);}}return{r:r,t:t};},dir:function(elem,dir){var matched=[],cur=elem[dir];while(cur&&cur!=document){if(cur.nodeType==1)matched.push(cur);cur=cur[dir];}return matched;},nth:function(cur,result,dir,elem){result=result||1;var num=0;for(;cur;cur=cur[dir])if(cur.nodeType==1&&++num==result)break;return cur;},sibling:function(n,elem){var r=[];for(;n;n=n.nextSibling){if(n.nodeType==1&&n!=elem)r.push(n);}return r;}});jQuery.event={add:function(elem,types,handler,data){if(elem.nodeType==3||elem.nodeType==8)return;if(jQuery.browser.msie&&elem.setInterval)elem=window;if(!handler.guid)handler.guid=this.guid++;if(data!=undefined){var fn=handler;handler=this.proxy(fn,function(){return fn.apply(this,arguments);});handler.data=data;}var events=jQuery.data(elem,"events")||jQuery.data(elem,"events",{}),handle=jQuery.data(elem,"handle")||jQuery.data(elem,"handle",function(){if(typeof jQuery!="undefined"&&!jQuery.event.triggered)return jQuery.event.handle.apply(arguments.callee.elem,arguments);});handle.elem=elem;jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];handler.type=parts[1];var handlers=events[type];if(!handlers){handlers=events[type]={};if(!jQuery.event.special[type]||jQuery.event.special[type].setup.call(elem)===false){if(elem.addEventListener)elem.addEventListener(type,handle,false);else if(elem.attachEvent)elem.attachEvent("on"+type,handle);}}handlers[handler.guid]=handler;jQuery.event.global[type]=true;});elem=null;},guid:1,global:{},remove:function(elem,types,handler){if(elem.nodeType==3||elem.nodeType==8)return;var events=jQuery.data(elem,"events"),ret,index;if(events){if(types==undefined||(typeof types=="string"&&types.charAt(0)=="."))for(var type in events)this.remove(elem,type+(types||""));else{if(types.type){handler=types.handler;types=types.type;}jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];if(events[type]){if(handler)delete events[type][handler.guid];else
+for(handler in events[type])if(!parts[1]||events[type][handler].type==parts[1])delete events[type][handler];for(ret in events[type])break;if(!ret){if(!jQuery.event.special[type]||jQuery.event.special[type].teardown.call(elem)===false){if(elem.removeEventListener)elem.removeEventListener(type,jQuery.data(elem,"handle"),false);else if(elem.detachEvent)elem.detachEvent("on"+type,jQuery.data(elem,"handle"));}ret=null;delete events[type];}}});}for(ret in events)break;if(!ret){var handle=jQuery.data(elem,"handle");if(handle)handle.elem=null;jQuery.removeData(elem,"events");jQuery.removeData(elem,"handle");}}},trigger:function(type,data,elem,donative,extra){data=jQuery.makeArray(data);if(type.indexOf("!")>=0){type=type.slice(0,-1);var exclusive=true;}if(!elem){if(this.global[type])jQuery("*").add([window,document]).trigger(type,data);}else{if(elem.nodeType==3||elem.nodeType==8)return undefined;var val,ret,fn=jQuery.isFunction(elem[type]||null),event=!data[0]||!data[0].preventDefault;if(event){data.unshift({type:type,target:elem,preventDefault:function(){},stopPropagation:function(){},timeStamp:now()});data[0][expando]=true;}data[0].type=type;if(exclusive)data[0].exclusive=true;var handle=jQuery.data(elem,"handle");if(handle)val=handle.apply(elem,data);if((!fn||(jQuery.nodeName(elem,'a')&&type=="click"))&&elem["on"+type]&&elem["on"+type].apply(elem,data)===false)val=false;if(event)data.shift();if(extra&&jQuery.isFunction(extra)){ret=extra.apply(elem,val==null?data:data.concat(val));if(ret!==undefined)val=ret;}if(fn&&donative!==false&&val!==false&&!(jQuery.nodeName(elem,'a')&&type=="click")){this.triggered=true;try{elem[type]();}catch(e){}}this.triggered=false;}return val;},handle:function(event){var val,ret,namespace,all,handlers;event=arguments[0]=jQuery.event.fix(event||window.event);namespace=event.type.split(".");event.type=namespace[0];namespace=namespace[1];all=!namespace&&!event.exclusive;handlers=(jQuery.data(this,"events")||{})[event.type];for(var j in handlers){var handler=handlers[j];if(all||handler.type==namespace){event.handler=handler;event.data=handler.data;ret=handler.apply(this,arguments);if(val!==false)val=ret;if(ret===false){event.preventDefault();event.stopPropagation();}}}return val;},fix:function(event){if(event[expando]==true)return event;var originalEvent=event;event={originalEvent:originalEvent};var props="altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target timeStamp toElement type view wheelDelta which".split(" ");for(var i=props.length;i;i--)event[props[i]]=originalEvent[props[i]];event[expando]=true;event.preventDefault=function(){if(originalEvent.preventDefault)originalEvent.preventDefault();originalEvent.returnValue=false;};event.stopPropagation=function(){if(originalEvent.stopPropagation)originalEvent.stopPropagation();originalEvent.cancelBubble=true;};event.timeStamp=event.timeStamp||now();if(!event.target)event.target=event.srcElement||document;if(event.target.nodeType==3)event.target=event.target.parentNode;if(!event.relatedTarget&&event.fromElement)event.relatedTarget=event.fromElement==event.target?event.toElement:event.fromElement;if(event.pageX==null&&event.clientX!=null){var doc=document.documentElement,body=document.body;event.pageX=event.clientX+(doc&&doc.scrollLeft||body&&body.scrollLeft||0)-(doc.clientLeft||0);event.pageY=event.clientY+(doc&&doc.scrollTop||body&&body.scrollTop||0)-(doc.clientTop||0);}if(!event.which&&((event.charCode||event.charCode===0)?event.charCode:event.keyCode))event.which=event.charCode||event.keyCode;if(!event.metaKey&&event.ctrlKey)event.metaKey=event.ctrlKey;if(!event.which&&event.button)event.which=(event.button&1?1:(event.button&2?3:(event.button&4?2:0)));return event;},proxy:function(fn,proxy){proxy.guid=fn.guid=fn.guid||proxy.guid||this.guid++;return proxy;},special:{ready:{setup:function(){bindReady();return;},teardown:function(){return;}},mouseenter:{setup:function(){if(jQuery.browser.msie)return false;jQuery(this).bind("mouseover",jQuery.event.special.mouseenter.handler);return true;},teardown:function(){if(jQuery.browser.msie)return false;jQuery(this).unbind("mouseover",jQuery.event.special.mouseenter.handler);return true;},handler:function(event){if(withinElement(event,this))return true;event.type="mouseenter";return jQuery.event.handle.apply(this,arguments);}},mouseleave:{setup:function(){if(jQuery.browser.msie)return false;jQuery(this).bind("mouseout",jQuery.event.special.mouseleave.handler);return true;},teardown:function(){if(jQuery.browser.msie)return false;jQuery(this).unbind("mouseout",jQuery.event.special.mouseleave.handler);return true;},handler:function(event){if(withinElement(event,this))return true;event.type="mouseleave";return jQuery.event.handle.apply(this,arguments);}}}};jQuery.fn.extend({bind:function(type,data,fn){return type=="unload"?this.one(type,data,fn):this.each(function(){jQuery.event.add(this,type,fn||data,fn&&data);});},one:function(type,data,fn){var one=jQuery.event.proxy(fn||data,function(event){jQuery(this).unbind(event,one);return(fn||data).apply(this,arguments);});return this.each(function(){jQuery.event.add(this,type,one,fn&&data);});},unbind:function(type,fn){return this.each(function(){jQuery.event.remove(this,type,fn);});},trigger:function(type,data,fn){return this.each(function(){jQuery.event.trigger(type,data,this,true,fn);});},triggerHandler:function(type,data,fn){return this[0]&&jQuery.event.trigger(type,data,this[0],false,fn);},toggle:function(fn){var args=arguments,i=1;while(i<args.length)jQuery.event.proxy(fn,args[i++]);return this.click(jQuery.event.proxy(fn,function(event){this.lastToggle=(this.lastToggle||0)%i;event.preventDefault();return args[this.lastToggle++].apply(this,arguments)||false;}));},hover:function(fnOver,fnOut){return this.bind('mouseenter',fnOver).bind('mouseleave',fnOut);},ready:function(fn){bindReady();if(jQuery.isReady)fn.call(document,jQuery);else
+jQuery.readyList.push(function(){return fn.call(this,jQuery);});return this;}});jQuery.extend({isReady:false,readyList:[],ready:function(){if(!jQuery.isReady){jQuery.isReady=true;if(jQuery.readyList){jQuery.each(jQuery.readyList,function(){this.call(document);});jQuery.readyList=null;}jQuery(document).triggerHandler("ready");}}});var readyBound=false;function bindReady(){if(readyBound)return;readyBound=true;if(document.addEventListener&&!jQuery.browser.opera)document.addEventListener("DOMContentLoaded",jQuery.ready,false);if(jQuery.browser.msie&&window==top)(function(){if(jQuery.isReady)return;try{document.documentElement.doScroll("left");}catch(error){setTimeout(arguments.callee,0);return;}jQuery.ready();})();if(jQuery.browser.opera)document.addEventListener("DOMContentLoaded",function(){if(jQuery.isReady)return;for(var i=0;i<document.styleSheets.length;i++)if(document.styleSheets[i].disabled){setTimeout(arguments.callee,0);return;}jQuery.ready();},false);if(jQuery.browser.safari){var numStyles;(function(){if(jQuery.isReady)return;if(document.readyState!="loaded"&&document.readyState!="complete"){setTimeout(arguments.callee,0);return;}if(numStyles===undefined)numStyles=jQuery("style, link[rel=stylesheet]").length;if(document.styleSheets.length!=numStyles){setTimeout(arguments.callee,0);return;}jQuery.ready();})();}jQuery.event.add(window,"load",jQuery.ready);}jQuery.each(("blur,focus,load,resize,scroll,unload,click,dblclick,"+"mousedown,mouseup,mousemove,mouseover,mouseout,change,select,"+"submit,keydown,keypress,keyup,error").split(","),function(i,name){jQuery.fn[name]=function(fn){return fn?this.bind(name,fn):this.trigger(name);};});var withinElement=function(event,elem){var parent=event.relatedTarget;while(parent&&parent!=elem)try{parent=parent.parentNode;}catch(error){parent=elem;}return parent==elem;};jQuery(window).bind("unload",function(){jQuery("*").add(document).unbind();});jQuery.fn.extend({_load:jQuery.fn.load,load:function(url,params,callback){if(typeof url!='string')return this._load(url);var off=url.indexOf(" ");if(off>=0){var selector=url.slice(off,url.length);url=url.slice(0,off);}callback=callback||function(){};var type="GET";if(params)if(jQuery.isFunction(params)){callback=params;params=null;}else{params=jQuery.param(params);type="POST";}var self=this;jQuery.ajax({url:url,type:type,dataType:"html",data:params,complete:function(res,status){if(status=="success"||status=="notmodified")self.html(selector?jQuery("<div/>").append(res.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(selector):res.responseText);self.each(callback,[res.responseText,status,res]);}});return this;},serialize:function(){return jQuery.param(this.serializeArray());},serializeArray:function(){return this.map(function(){return jQuery.nodeName(this,"form")?jQuery.makeArray(this.elements):this;}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password/i.test(this.type));}).map(function(i,elem){var val=jQuery(this).val();return val==null?null:val.constructor==Array?jQuery.map(val,function(val,i){return{name:elem.name,value:val};}):{name:elem.name,value:val};}).get();}});jQuery.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(i,o){jQuery.fn[o]=function(f){return this.bind(o,f);};});var jsc=now();jQuery.extend({get:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data=null;}return jQuery.ajax({type:"GET",url:url,data:data,success:callback,dataType:type});},getScript:function(url,callback){return jQuery.get(url,null,callback,"script");},getJSON:function(url,data,callback){return jQuery.get(url,data,callback,"json");},post:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data={};}return jQuery.ajax({type:"POST",url:url,data:data,success:callback,dataType:type});},ajaxSetup:function(settings){jQuery.extend(jQuery.ajaxSettings,settings);},ajaxSettings:{url:location.href,global:true,type:"GET",timeout:0,contentType:"application/x-www-form-urlencoded",processData:true,async:true,data:null,username:null,password:null,accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(s){s=jQuery.extend(true,s,jQuery.extend(true,{},jQuery.ajaxSettings,s));var jsonp,jsre=/=\?(&|$)/g,status,data,type=s.type.toUpperCase();if(s.data&&s.processData&&typeof s.data!="string")s.data=jQuery.param(s.data);if(s.dataType=="jsonp"){if(type=="GET"){if(!s.url.match(jsre))s.url+=(s.url.match(/\?/)?"&":"?")+(s.jsonp||"callback")+"=?";}else if(!s.data||!s.data.match(jsre))s.data=(s.data?s.data+"&":"")+(s.jsonp||"callback")+"=?";s.dataType="json";}if(s.dataType=="json"&&(s.data&&s.data.match(jsre)||s.url.match(jsre))){jsonp="jsonp"+jsc++;if(s.data)s.data=(s.data+"").replace(jsre,"="+jsonp+"$1");s.url=s.url.replace(jsre,"="+jsonp+"$1");s.dataType="script";window[jsonp]=function(tmp){data=tmp;success();complete();window[jsonp]=undefined;try{delete window[jsonp];}catch(e){}if(head)head.removeChild(script);};}if(s.dataType=="script"&&s.cache==null)s.cache=false;if(s.cache===false&&type=="GET"){var ts=now();var ret=s.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+ts+"$2");s.url=ret+((ret==s.url)?(s.url.match(/\?/)?"&":"?")+"_="+ts:"");}if(s.data&&type=="GET"){s.url+=(s.url.match(/\?/)?"&":"?")+s.data;s.data=null;}if(s.global&&!jQuery.active++)jQuery.event.trigger("ajaxStart");var remote=/^(?:\w+:)?\/\/([^\/?#]+)/;if(s.dataType=="script"&&type=="GET"&&remote.test(s.url)&&remote.exec(s.url)[1]!=location.host){var head=document.getElementsByTagName("head")[0];var script=document.createElement("script");script.src=s.url;if(s.scriptCharset)script.charset=s.scriptCharset;if(!jsonp){var done=false;script.onload=script.onreadystatechange=function(){if(!done&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){done=true;success();complete();head.removeChild(script);}};}head.appendChild(script);return undefined;}var requestDone=false;var xhr=window.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest();if(s.username)xhr.open(type,s.url,s.async,s.username,s.password);else
+xhr.open(type,s.url,s.async);try{if(s.data)xhr.setRequestHeader("Content-Type",s.contentType);if(s.ifModified)xhr.setRequestHeader("If-Modified-Since",jQuery.lastModified[s.url]||"Thu, 01 Jan 1970 00:00:00 GMT");xhr.setRequestHeader("X-Requested-With","XMLHttpRequest");xhr.setRequestHeader("Accept",s.dataType&&s.accepts[s.dataType]?s.accepts[s.dataType]+", */*":s.accepts._default);}catch(e){}if(s.beforeSend&&s.beforeSend(xhr,s)===false){s.global&&jQuery.active--;xhr.abort();return false;}if(s.global)jQuery.event.trigger("ajaxSend",[xhr,s]);var onreadystatechange=function(isTimeout){if(!requestDone&&xhr&&(xhr.readyState==4||isTimeout=="timeout")){requestDone=true;if(ival){clearInterval(ival);ival=null;}status=isTimeout=="timeout"&&"timeout"||!jQuery.httpSuccess(xhr)&&"error"||s.ifModified&&jQuery.httpNotModified(xhr,s.url)&&"notmodified"||"success";if(status=="success"){try{data=jQuery.httpData(xhr,s.dataType,s.dataFilter);}catch(e){status="parsererror";}}if(status=="success"){var modRes;try{modRes=xhr.getResponseHeader("Last-Modified");}catch(e){}if(s.ifModified&&modRes)jQuery.lastModified[s.url]=modRes;if(!jsonp)success();}else
+jQuery.handleError(s,xhr,status);complete();if(s.async)xhr=null;}};if(s.async){var ival=setInterval(onreadystatechange,13);if(s.timeout>0)setTimeout(function(){if(xhr){xhr.abort();if(!requestDone)onreadystatechange("timeout");}},s.timeout);}try{xhr.send(s.data);}catch(e){jQuery.handleError(s,xhr,null,e);}if(!s.async)onreadystatechange();function success(){if(s.success)s.success(data,status);if(s.global)jQuery.event.trigger("ajaxSuccess",[xhr,s]);}function complete(){if(s.complete)s.complete(xhr,status);if(s.global)jQuery.event.trigger("ajaxComplete",[xhr,s]);if(s.global&&!--jQuery.active)jQuery.event.trigger("ajaxStop");}return xhr;},handleError:function(s,xhr,status,e){if(s.error)s.error(xhr,status,e);if(s.global)jQuery.event.trigger("ajaxError",[xhr,s,e]);},active:0,httpSuccess:function(xhr){try{return!xhr.status&&location.protocol=="file:"||(xhr.status>=200&&xhr.status<300)||xhr.status==304||xhr.status==1223||jQuery.browser.safari&&xhr.status==undefined;}catch(e){}return false;},httpNotModified:function(xhr,url){try{var xhrRes=xhr.getResponseHeader("Last-Modified");return xhr.status==304||xhrRes==jQuery.lastModified[url]||jQuery.browser.safari&&xhr.status==undefined;}catch(e){}return false;},httpData:function(xhr,type,filter){var ct=xhr.getResponseHeader("content-type"),xml=type=="xml"||!type&&ct&&ct.indexOf("xml")>=0,data=xml?xhr.responseXML:xhr.responseText;if(xml&&data.documentElement.tagName=="parsererror")throw"parsererror";if(filter)data=filter(data,type);if(type=="script")jQuery.globalEval(data);if(type=="json")data=eval("("+data+")");return data;},param:function(a){var s=[];if(a.constructor==Array||a.jquery)jQuery.each(a,function(){s.push(encodeURIComponent(this.name)+"="+encodeURIComponent(this.value));});else
+for(var j in a)if(a[j]&&a[j].constructor==Array)jQuery.each(a[j],function(){s.push(encodeURIComponent(j)+"="+encodeURIComponent(this));});else
+s.push(encodeURIComponent(j)+"="+encodeURIComponent(jQuery.isFunction(a[j])?a[j]():a[j]));return s.join("&").replace(/%20/g,"+");}});jQuery.fn.extend({show:function(speed,callback){return speed?this.animate({height:"show",width:"show",opacity:"show"},speed,callback):this.filter(":hidden").each(function(){this.style.display=this.oldblock||"";if(jQuery.css(this,"display")=="none"){var elem=jQuery("<"+this.tagName+" />").appendTo("body");this.style.display=elem.css("display");if(this.style.display=="none")this.style.display="block";elem.remove();}}).end();},hide:function(speed,callback){return speed?this.animate({height:"hide",width:"hide",opacity:"hide"},speed,callback):this.filter(":visible").each(function(){this.oldblock=this.oldblock||jQuery.css(this,"display");this.style.display="none";}).end();},_toggle:jQuery.fn.toggle,toggle:function(fn,fn2){return jQuery.isFunction(fn)&&jQuery.isFunction(fn2)?this._toggle.apply(this,arguments):fn?this.animate({height:"toggle",width:"toggle",opacity:"toggle"},fn,fn2):this.each(function(){jQuery(this)[jQuery(this).is(":hidden")?"show":"hide"]();});},slideDown:function(speed,callback){return this.animate({height:"show"},speed,callback);},slideUp:function(speed,callback){return this.animate({height:"hide"},speed,callback);},slideToggle:function(speed,callback){return this.animate({height:"toggle"},speed,callback);},fadeIn:function(speed,callback){return this.animate({opacity:"show"},speed,callback);},fadeOut:function(speed,callback){return this.animate({opacity:"hide"},speed,callback);},fadeTo:function(speed,to,callback){return this.animate({opacity:to},speed,callback);},animate:function(prop,speed,easing,callback){var optall=jQuery.speed(speed,easing,callback);return this[optall.queue===false?"each":"queue"](function(){if(this.nodeType!=1)return false;var opt=jQuery.extend({},optall),p,hidden=jQuery(this).is(":hidden"),self=this;for(p in prop){if(prop[p]=="hide"&&hidden||prop[p]=="show"&&!hidden)return opt.complete.call(this);if(p=="height"||p=="width"){opt.display=jQuery.css(this,"display");opt.overflow=this.style.overflow;}}if(opt.overflow!=null)this.style.overflow="hidden";opt.curAnim=jQuery.extend({},prop);jQuery.each(prop,function(name,val){var e=new jQuery.fx(self,opt,name);if(/toggle|show|hide/.test(val))e[val=="toggle"?hidden?"show":"hide":val](prop);else{var parts=val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),start=e.cur(true)||0;if(parts){var end=parseFloat(parts[2]),unit=parts[3]||"px";if(unit!="px"){self.style[name]=(end||1)+unit;start=((end||1)/e.cur(true))*start;self.style[name]=start+unit;}if(parts[1])end=((parts[1]=="-="?-1:1)*end)+start;e.custom(start,end,unit);}else
+e.custom(start,val,"");}});return true;});},queue:function(type,fn){if(jQuery.isFunction(type)||(type&&type.constructor==Array)){fn=type;type="fx";}if(!type||(typeof type=="string"&&!fn))return queue(this[0],type);return this.each(function(){if(fn.constructor==Array)queue(this,type,fn);else{queue(this,type).push(fn);if(queue(this,type).length==1)fn.call(this);}});},stop:function(clearQueue,gotoEnd){var timers=jQuery.timers;if(clearQueue)this.queue([]);this.each(function(){for(var i=timers.length-1;i>=0;i--)if(timers[i].elem==this){if(gotoEnd)timers[i](true);timers.splice(i,1);}});if(!gotoEnd)this.dequeue();return this;}});var queue=function(elem,type,array){if(elem){type=type||"fx";var q=jQuery.data(elem,type+"queue");if(!q||array)q=jQuery.data(elem,type+"queue",jQuery.makeArray(array));}return q;};jQuery.fn.dequeue=function(type){type=type||"fx";return this.each(function(){var q=queue(this,type);q.shift();if(q.length)q[0].call(this);});};jQuery.extend({speed:function(speed,easing,fn){var opt=speed&&speed.constructor==Object?speed:{complete:fn||!fn&&easing||jQuery.isFunction(speed)&&speed,duration:speed,easing:fn&&easing||easing&&easing.constructor!=Function&&easing};opt.duration=(opt.duration&&opt.duration.constructor==Number?opt.duration:jQuery.fx.speeds[opt.duration])||jQuery.fx.speeds.def;opt.old=opt.complete;opt.complete=function(){if(opt.queue!==false)jQuery(this).dequeue();if(jQuery.isFunction(opt.old))opt.old.call(this);};return opt;},easing:{linear:function(p,n,firstNum,diff){return firstNum+diff*p;},swing:function(p,n,firstNum,diff){return((-Math.cos(p*Math.PI)/2)+0.5)*diff+firstNum;}},timers:[],timerId:null,fx:function(elem,options,prop){this.options=options;this.elem=elem;this.prop=prop;if(!options.orig)options.orig={};}});jQuery.fx.prototype={update:function(){if(this.options.step)this.options.step.call(this.elem,this.now,this);(jQuery.fx.step[this.prop]||jQuery.fx.step._default)(this);if(this.prop=="height"||this.prop=="width")this.elem.style.display="block";},cur:function(force){if(this.elem[this.prop]!=null&&this.elem.style[this.prop]==null)return this.elem[this.prop];var r=parseFloat(jQuery.css(this.elem,this.prop,force));return r&&r>-10000?r:parseFloat(jQuery.curCSS(this.elem,this.prop))||0;},custom:function(from,to,unit){this.startTime=now();this.start=from;this.end=to;this.unit=unit||this.unit||"px";this.now=this.start;this.pos=this.state=0;this.update();var self=this;function t(gotoEnd){return self.step(gotoEnd);}t.elem=this.elem;jQuery.timers.push(t);if(jQuery.timerId==null){jQuery.timerId=setInterval(function(){var timers=jQuery.timers;for(var i=0;i<timers.length;i++)if(!timers[i]())timers.splice(i--,1);if(!timers.length){clearInterval(jQuery.timerId);jQuery.timerId=null;}},13);}},show:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.show=true;this.custom(0,this.cur());if(this.prop=="width"||this.prop=="height")this.elem.style[this.prop]="1px";jQuery(this.elem).show();},hide:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0);},step:function(gotoEnd){var t=now();if(gotoEnd||t>this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var done=true;for(var i in this.options.curAnim)if(this.options.curAnim[i]!==true)done=false;if(done){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(jQuery.css(this.elem,"display")=="none")this.elem.style.display="block";}if(this.options.hide)this.elem.style.display="none";if(this.options.hide||this.options.show)for(var p in this.options.curAnim)jQuery.attr(this.elem.style,p,this.options.orig[p]);}if(done)this.options.complete.call(this.elem);return false;}else{var n=t-this.startTime;this.state=n/this.options.duration;this.pos=jQuery.easing[this.options.easing||(jQuery.easing.swing?"swing":"linear")](this.state,n,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update();}return true;}};jQuery.extend(jQuery.fx,{speeds:{slow:600,fast:200,def:400},step:{scrollLeft:function(fx){fx.elem.scrollLeft=fx.now;},scrollTop:function(fx){fx.elem.scrollTop=fx.now;},opacity:function(fx){jQuery.attr(fx.elem.style,"opacity",fx.now);},_default:function(fx){fx.elem.style[fx.prop]=fx.now+fx.unit;}}});jQuery.fn.offset=function(){var left=0,top=0,elem=this[0],results;if(elem)with(jQuery.browser){var parent=elem.parentNode,offsetChild=elem,offsetParent=elem.offsetParent,doc=elem.ownerDocument,safari2=safari&&parseInt(version)<522&&!/adobeair/i.test(userAgent),css=jQuery.curCSS,fixed=css(elem,"position")=="fixed";if(elem.getBoundingClientRect){var box=elem.getBoundingClientRect();add(box.left+Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),box.top+Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));add(-doc.documentElement.clientLeft,-doc.documentElement.clientTop);}else{add(elem.offsetLeft,elem.offsetTop);while(offsetParent){add(offsetParent.offsetLeft,offsetParent.offsetTop);if(mozilla&&!/^t(able|d|h)$/i.test(offsetParent.tagName)||safari&&!safari2)border(offsetParent);if(!fixed&&css(offsetParent,"position")=="fixed")fixed=true;offsetChild=/^body$/i.test(offsetParent.tagName)?offsetChild:offsetParent;offsetParent=offsetParent.offsetParent;}while(parent&&parent.tagName&&!/^body|html$/i.test(parent.tagName)){if(!/^inline|table.*$/i.test(css(parent,"display")))add(-parent.scrollLeft,-parent.scrollTop);if(mozilla&&css(parent,"overflow")!="visible")border(parent);parent=parent.parentNode;}if((safari2&&(fixed||css(offsetChild,"position")=="absolute"))||(mozilla&&css(offsetChild,"position")!="absolute"))add(-doc.body.offsetLeft,-doc.body.offsetTop);if(fixed)add(Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));}results={top:top,left:left};}function border(elem){add(jQuery.curCSS(elem,"borderLeftWidth",true),jQuery.curCSS(elem,"borderTopWidth",true));}function add(l,t){left+=parseInt(l,10)||0;top+=parseInt(t,10)||0;}return results;};jQuery.fn.extend({position:function(){var left=0,top=0,results;if(this[0]){var offsetParent=this.offsetParent(),offset=this.offset(),parentOffset=/^body|html$/i.test(offsetParent[0].tagName)?{top:0,left:0}:offsetParent.offset();offset.top-=num(this,'marginTop');offset.left-=num(this,'marginLeft');parentOffset.top+=num(offsetParent,'borderTopWidth');parentOffset.left+=num(offsetParent,'borderLeftWidth');results={top:offset.top-parentOffset.top,left:offset.left-parentOffset.left};}return results;},offsetParent:function(){var offsetParent=this[0].offsetParent;while(offsetParent&&(!/^body|html$/i.test(offsetParent.tagName)&&jQuery.css(offsetParent,'position')=='static'))offsetParent=offsetParent.offsetParent;return jQuery(offsetParent);}});jQuery.each(['Left','Top'],function(i,name){var method='scroll'+name;jQuery.fn[method]=function(val){if(!this[0])return;return val!=undefined?this.each(function(){this==window||this==document?window.scrollTo(!i?val:jQuery(window).scrollLeft(),i?val:jQuery(window).scrollTop()):this[method]=val;}):this[0]==window||this[0]==document?self[i?'pageYOffset':'pageXOffset']||jQuery.boxModel&&document.documentElement[method]||document.body[method]:this[0][method];};});jQuery.each(["Height","Width"],function(i,name){var tl=i?"Left":"Top",br=i?"Right":"Bottom";jQuery.fn["inner"+name]=function(){return this[name.toLowerCase()]()+num(this,"padding"+tl)+num(this,"padding"+br);};jQuery.fn["outer"+name]=function(margin){return this["inner"+name]()+num(this,"border"+tl+"Width")+num(this,"border"+br+"Width")+(margin?num(this,"margin"+tl)+num(this,"margin"+br):0);};});})();
View
96 samples/ruby-login-server/public/js/openid-en.js
@@ -0,0 +1,96 @@
+/*
+ Simple OpenID Plugin
+ http://code.google.com/p/openid-selector/
+
+ This code is licensed under the New BSD License.
+*/
+
+var providers_large = {
+ google : {
+ name : 'Google',
+ url : 'https://www.google.com/accounts/o8/id'
+ },
+ yahoo : {
+ name : 'Yahoo',
+ url : 'http://me.yahoo.com/'
+ },
+ aol : {
+ name : 'AOL',
+ label : 'Enter your AOL screenname.',
+ url : 'http://openid.aol.com/{username}'
+ },
+ myopenid : {
+ name : 'MyOpenID',
+ label : 'Enter your MyOpenID username.',
+ url : 'http://{username}.myopenid.com/'
+ },
+ openid : {
+ name : 'OpenID',
+ label : 'Enter your OpenID.',
+ url : null
+ }
+};
+
+var providers_small = {
+ livejournal : {
+ name : 'LiveJournal',
+ label : 'Enter your Livejournal username.',
+ url : 'http://{username}.livejournal.com/'
+ },
+ /* flickr: {
+ name: 'Flickr',
+ label: 'Enter your Flickr username.',
+ url: 'http://flickr.com/{username}/'
+ }, */
+ /* technorati: {
+ name: 'Technorati',
+ label: 'Enter your Technorati username.',
+ url: 'http://technorati.com/people/technorati/{username}/'
+ }, */
+ wordpress : {
+ name : 'Wordpress',
+ label : 'Enter your Wordpress.com username.',
+ url : 'http://{username}.wordpress.com/'
+ },
+ blogger : {
+ name : 'Blogger',
+ label : 'Your Blogger account',
+ url : 'http://{username}.blogspot.com/'
+ },
+ verisign : {
+ name : 'Verisign',
+ label : 'Your Verisign username',
+ url : 'http://{username}.pip.verisignlabs.com/'
+ },
+ /* vidoop: {
+ name: 'Vidoop',
+ label: 'Your Vidoop username',
+ url: 'http://{username}.myvidoop.com/'
+ }, */
+ /* launchpad: {
+ name: 'Launchpad',
+ label: 'Your Launchpad username',
+ url: 'https://launchpad.net/~{username}'
+ }, */
+ claimid : {
+ name : 'ClaimID',
+ label : 'Your ClaimID username',
+ url : 'http://claimid.com/{username}'
+ },
+ clickpass : {
+ name : 'ClickPass',
+ label : 'Enter your ClickPass username',
+ url : 'http://clickpass.com/public/{username}'
+ },
+ google_profile : {
+ name : 'Google Profile',
+ label : 'Enter your Google Profile username',
+ url : 'http://www.google.com/profiles/{username}'
+ }
+};
+
+openid.locale = 'en';
+openid.sprite = 'en'; // reused in german& japan localization
+openid.demo_text = 'In client demo mode. Normally would have submitted OpenID:';
+openid.signin_text = 'Sign-In';
+openid.image_title = 'log in with {provider}';
View
202 samples/ruby-login-server/public/js/openid-jquery.js
@@ -0,0 +1,202 @@
+/*
+ Simple OpenID Plugin
+ http://code.google.com/p/openid-selector/
+
+ This code is licensed under the New BSD License.
+*/
+
+var providers;
+var openid;
+(function ($) {
+openid = {
+ version : '1.3', // version constant
+ demo : false,
+ demo_text : null,
+ cookie_expires : 6 * 30, // 6 months.
+ cookie_name : 'openid_provider',
+ cookie_path : '/',
+
+ img_path : 'images/',
+ locale : null, // is set in openid-<locale>.js
+ sprite : null, // usually equals to locale, is set in
+ // openid-<locale>.js
+ signin_text : null, // text on submit button on the form
+ all_small : false, // output large providers w/ small icons
+ no_sprite : false, // don't use sprite image
+ image_title : '{provider}', // for image title
+
+ input_id : null,
+ provider_url : null,
+ provider_id : null,
+
+ /**
+ * Class constructor
+ *
+ * @return {Void}
+ */
+ init : function(input_id) {
+ providers = $.extend({}, providers_large, providers_small);
+ var openid_btns = $('#openid_btns');
+ this.input_id = input_id;
+ $('#openid_choice').show();
+ $('#openid_input_area').empty();
+ var i = 0;
+ // add box for each provider
+ for (id in providers_large) {
+ box = this.getBoxHTML(id, providers_large[id], (this.all_small ? 'small' : 'large'), i++);
+ openid_btns.append(box);
+ }
+ if (providers_small) {
+ openid_btns.append('<br/>');
+ for (id in providers_small) {
+ box = this.getBoxHTML(id, providers_small[id], 'small', i++);
+ openid_btns.append(box);
+ }
+ }
+ $('#openid_form').submit(this.submit);
+ var box_id = this.readCookie();
+ if (box_id) {
+ this.signin(box_id, true);
+ }
+ },
+
+ /**
+ * @return {String}
+ */
+ getBoxHTML : function(box_id, provider, box_size, index) {
+ if (this.no_sprite) {
+ var image_ext = box_size == 'small' ? '.ico.gif' : '.gif';
+ return '<a title="' + this.image_title.replace('{provider}', provider["name"]) + '" href="javascript:openid.signin(\'' + box_id + '\');"'
+ + ' style="background: #FFF url(' + this.img_path + '../images.' + box_size + '/' + box_id + image_ext + ') no-repeat center center" '
+ + 'class="' + box_id + ' openid_' + box_size + '_btn"></a>';
+ }
+ var x = box_size == 'small' ? -index * 24 : -index * 100;
+ var y = box_size == 'small' ? -60 : 0;
+ return '<a title="' + this.image_title.replace('{provider}', provider["name"]) + '" href="javascript:openid.signin(\'' + box_id + '\');"'
+ + ' style="background: #FFF url(' + this.img_path + 'openid-providers-' + this.sprite + '.png); background-position: ' + x + 'px ' + y + 'px" '
+ + 'class="' + box_id + ' openid_' + box_size + '_btn"></a>';
+ },
+
+ /**
+ * Provider image click
+ *
+ * @return {Void}
+ */
+ signin : function(box_id, onload) {
+ var provider = providers[box_id];
+ if (!provider) {
+ return;
+ }
+ this.highlight(box_id);
+ this.setCookie(box_id);
+ this.provider_id = box_id;
+ this.provider_url = provider['url'];
+ // prompt user for input?
+ if (provider['label']) {
+ this.useInputBox(provider);
+ } else {
+ $('#openid_input_area').empty();
+ if (!onload) {
+ $('#openid_form').submit();
+ }
+ }
+ },
+
+ /**
+ * Sign-in button click
+ *
+ * @return {Boolean}
+ */
+ submit : function() {
+ var url = openid.provider_url;
+ if (url) {
+ url = url.replace('{username}', $('#openid_username').val());
+ openid.setOpenIdUrl(url);
+ }
+ if (openid.demo) {
+ alert(openid.demo_text + "\r\n" + document.getElementById(openid.input_id).value);
+ return false;
+ }
+ if (url.indexOf("javascript:") == 0) {
+ url = url.substr("javascript:".length);
+ eval(url);
+ return false;
+ }
+ return true;
+ },
+
+ /**
+ * @return {Void}
+ */
+ setOpenIdUrl : function(url) {
+ var hidden = document.getElementById(this.input_id);
+ if (hidden != null) {
+ hidden.value = url;
+ } else {
+ $('#openid_form').append('<input type="hidden" id="' + this.input_id + '" name="' + this.input_id + '" value="' + url + '"/>');
+ }
+ },
+
+ /**
+ * @return {Void}
+ */
+ highlight : function(box_id) {
+ // remove previous highlight.
+ var highlight = $('#openid_highlight');
+ if (highlight) {
+ highlight.replaceWith($('#openid_highlight a')[0]);
+ }
+ // add new highlight.
+ $('.' + box_id).wrap('<div id="openid_highlight"></div>');
+ },
+
+ setCookie : function(value) {
+ var date = new Date();
+ date.setTime(date.getTime() + (this.cookie_expires * 24 * 60 * 60 * 1000));
+ var expires = "; expires=" + date.toGMTString();
+ document.cookie = this.cookie_name + "=" + value + expires + "; path=" + this.cookie_path;
+ },
+
+ readCookie : function() {
+ var nameEQ = this.cookie_name + "=";
+ var ca = document.cookie.split(';');
+ for ( var i = 0; i < ca.length; i++) {
+ var c = ca[i];
+ while (c.charAt(0) == ' ')
+ c = c.substring(1, c.length);
+ if (c.indexOf(nameEQ) == 0)
+ return c.substring(nameEQ.length, c.length);
+ }
+ return null;
+ },
+
+ /**
+ * @return {Void}
+ */
+ useInputBox : function(provider) {
+ var input_area = $('#openid_input_area');
+ var html = '';
+ var id = 'openid_username';
+ var value = '';
+ var label = provider['label'];
+ var style = '';
+ if (label) {
+ html = '<p>' + label + '</p>';
+ }
+ if (provider['name'] == 'OpenID') {
+ id = this.input_id;
+ value = 'http://';
+ style = 'background: #FFF url(' + this.img_path + 'openid-inputicon.gif) no-repeat scroll 0 50%; padding-left:18px;';
+ }
+ html += '<input id="' + id + '" type="text" style="' + style + '" name="' + id + '" value="' + value + '" />'
+ + '<input id="openid_submit" type="submit" value="' + this.signin_text + '"/>';
+ input_area.empty();
+ input_area.append(html);
+ $('#' + id).focus();
+ },
+
+ setDemoMode : function(demoMode) {
+ this.demo = demoMode;
+ }
+};
+})(jQuery);
View
11 samples/ruby-login-server/views/confirm.erb
@@ -0,0 +1,11 @@
+<html>
+ <head><title>Confirm authorization request</title></head>
+ <body>
+ <h4>Do you want to authorize the application "<%= client_id %>" access to <%= scopes %> </h4>
+ <form action="/confirm" method="POST">
+ <input type="radio" name="choice" value="yes" /> Yes<br />
+ <input type="radio" name="choice" value="no" /> No<br/>
+ <input type="submit" />
+ </form>
+ </body>
+</html>
View
47 samples/ruby-login-server/views/login.erb
@@ -0,0 +1,47 @@
+<html>
+ <head>
+ <title>Welcome</title>
+ <!-- Simple OpenID Selector from http://code.google.com/p/openid-selector/-->
+ <link type="text/css" rel="stylesheet" href="css/openid.css" />
+ <script type="text/javascript" src="js/jquery-1.2.6.min.js"></script>
+ <script type="text/javascript" src="js/openid-jquery.js"></script>
+ <script type="text/javascript" src="js/openid-en.js"></script>
+ <script type="text/javascript">
+ $(document).ready(function() {
+ openid.init('openid_identifier');
+ });
+ </script>
+ <!-- /Simple OpenID Selector -->
+ </head>
+ <body onload="document.getElementsByName('username')[0].focus()">
+ <h4>Please login</h4>
+ <%= "<strong style=\"color:red\">Login error</strong><br/>" unless params["error"].nil? %>
+ <form name="login" method="POST" action="/login">
+ <table>
+ <tr><td><p>Username: </p></td><td><input type="text" name="username"/></td></tr>
+ <tr><td><p>Password: </p></td><td><input type="password" name="password"/></td></tr>
+ <tr><td><input type="submit" /></td></tr>
+ </table>
+ </form>
+ <!-- Simple OpenID Selector -->
+ <form action="/openid/start" method="get" id="openid_form">
+ <input type="hidden" name="action" value="verify" />
+ <fieldset>
+ <legend>Sign-in or Create New Account</legend>
+ <div id="openid_choice">
+ <p>Please click your account provider:</p>
+ <div id="openid_btns"></div>
+ </div>
+ <div id="openid_input_area">
+ <input id="openid_identifier" name="openid_identifier" type="text" value="http://" />
+ <input id="openid_submit" type="submit" value="Sign-In"/>
+ </div>
+ <noscript>
+ <p>OpenID is service that allows you to log-on to many different websites using a single indentity.
+ Find out <a href="http://openid.net/what/">more about OpenID</a> and <a href="http://openid.net/get/">how to get an OpenID enabled account</a>.</p>
+ </noscript>
+ </fieldset>
+ </form>
+ <!-- /Simple OpenID Selector -->
+ </body>
+</html>

0 comments on commit c22e65f

Please sign in to comment.
Something went wrong with that request. Please try again.