diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2261631 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +.bundle +db/*.sqlite3 +log/resque_worker.* +log/*.log* +log/*.db +tmp/ +dump.rdb +.DS_Store +public/assets/ +public/system/ +public/uploads/ diff --git a/.rbenv-version b/.rbenv-version new file mode 100644 index 0000000..9bbcf15 --- /dev/null +++ b/.rbenv-version @@ -0,0 +1 @@ +1.9.3-p0 diff --git a/.rvmrc b/.rvmrc new file mode 100644 index 0000000..f73d5d7 --- /dev/null +++ b/.rvmrc @@ -0,0 +1 @@ +rvm 1.9.2 diff --git a/Capfile b/Capfile new file mode 100644 index 0000000..e04728e --- /dev/null +++ b/Capfile @@ -0,0 +1,4 @@ +load 'deploy' if respond_to?(:namespace) # cap2 differentiator +Dir['vendor/plugins/*/recipes/*.rb'].each { |plugin| load(plugin) } + +load 'config/deploy' # remove this line to skip loading any of the default tasks \ No newline at end of file diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..e646ef8 --- /dev/null +++ b/Gemfile @@ -0,0 +1,42 @@ +source 'http://rubygems.org' +source 'http://gems.github.com' + +gem 'rails', '3.0.9' +gem 'jquery-rails' +gem 'capistrano', group: :development +gem 'haml' +gem 'will_paginate', '>=3.0.pre2' +gem "state_machine", '>=0.9.4' +gem 'authlogic' +gem "activemerchant" +gem "money" +gem "recaptcha", require: "recaptcha/rails" +gem "tabs_on_rails", ">=1.3.1" +gem "bartt-ssl_requirement", require: 'ssl_requirement' +gem "jammit" +gem 'spectator-validates_email', require: 'validates_email' + +# Image processing. Currently there is an issue with Ruby ReadLine so we use a custom ImageScience. +gem 'carrierwave' +gem 'image_science', git: "git://github.com/asynchrony/image_science.git" + +gem 'gibbon', group: :production + +# Caching +gem 'redis' +gem 'redis-store', '>=1.0.0.beta4' + +# Background jobs +gem 'stalker' +gem 'daemon-spawn' +gem "whenever" + +# Database +gem 'sqlite3-ruby', require: 'sqlite3', group: [:development, :test] +gem "mysql2", "~> 0.2.7", group: [:production, :staging] + +# Testing and monitoring +gem "factory_girl_rails", group: [:test, :development] +gem "timecop", group: :test +gem "newrelic_rpm", ">= 3.1.0" +gem 'hoptoad_notifier' \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..03f7237 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,192 @@ +GIT + remote: git://github.com/asynchrony/image_science.git + revision: d33dbad3efaef4ddc3785e135be4006f9e80d2d9 + specs: + image_science (1.3.2.1.Asynchrony) + +GEM + remote: http://rubygems.org/ + remote: http://gems.github.com/ + specs: + POpen4 (0.1.4) + Platform (>= 0.4.0) + open4 + Platform (0.4.0) + aaronh-chronic (0.3.9) + abstract (1.0.0) + actionmailer (3.0.9) + actionpack (= 3.0.9) + mail (~> 2.2.19) + actionpack (3.0.9) + activemodel (= 3.0.9) + activesupport (= 3.0.9) + builder (~> 2.1.2) + erubis (~> 2.6.6) + i18n (~> 0.5.0) + rack (~> 1.2.1) + rack-mount (~> 0.6.14) + rack-test (~> 0.5.7) + tzinfo (~> 0.3.23) + activemerchant (1.16.0) + activesupport (>= 2.3.11) + braintree (>= 2.0.0) + builder (>= 2.0.0) + json (>= 1.5.1) + activemodel (3.0.9) + activesupport (= 3.0.9) + builder (~> 2.1.2) + i18n (~> 0.5.0) + activerecord (3.0.9) + activemodel (= 3.0.9) + activesupport (= 3.0.9) + arel (~> 2.0.10) + tzinfo (~> 0.3.23) + activeresource (3.0.9) + activemodel (= 3.0.9) + activesupport (= 3.0.9) + activesupport (3.0.9) + arel (2.0.10) + authlogic (3.0.3) + activerecord (>= 3.0.7) + activerecord (>= 3.0.7) + bartt-ssl_requirement (1.2.7) + beanstalk-client (1.1.0) + braintree (2.10.1) + builder (>= 2.0.0) + builder (2.1.2) + capistrano (2.6.0) + highline + net-scp (>= 1.0.0) + net-sftp (>= 2.0.0) + net-ssh (>= 2.0.14) + net-ssh-gateway (>= 1.1.0) + carrierwave (0.5.6) + activesupport (~> 3.0) + crack (0.1.8) + daemon-spawn (0.4.2) + erubis (2.6.6) + abstract (>= 1.0.0) + factory_girl (1.3.3) + factory_girl_rails (1.0.1) + factory_girl (~> 1.3) + railties (>= 3.0.0) + gibbon (0.1.7) + activesupport (> 3.0.0) + httparty (> 0.6.0) + json (> 1.4.0) + haml (3.1.2) + highline (1.6.2) + hoptoad_notifier (2.4.11) + activesupport + builder + httparty (0.7.8) + crack (= 0.1.8) + i18n (0.5.0) + jammit (0.6.3) + yui-compressor (>= 0.9.3) + jquery-rails (1.0.12) + railties (~> 3.0) + thor (~> 0.14) + json (1.5.3) + json_pure (1.5.3) + mail (2.2.19) + activesupport (>= 2.3.6) + i18n (>= 0.4.0) + mime-types (~> 1.16) + treetop (~> 1.4.8) + mime-types (1.16) + money (3.7.1) + i18n (~> 0.4) + mysql2 (0.2.11) + net-scp (1.0.4) + net-ssh (>= 1.99.1) + net-sftp (2.0.5) + net-ssh (>= 2.0.9) + net-ssh (2.1.4) + net-ssh-gateway (1.1.0) + net-ssh (>= 1.99.1) + newrelic_rpm (3.1.0) + open4 (1.1.0) + polyglot (0.3.1) + rack (1.2.3) + rack-mount (0.6.14) + rack (>= 1.0.0) + rack-test (0.5.7) + rack (>= 1.0) + rails (3.0.9) + actionmailer (= 3.0.9) + actionpack (= 3.0.9) + activerecord (= 3.0.9) + activeresource (= 3.0.9) + activesupport (= 3.0.9) + bundler (~> 1.0) + railties (= 3.0.9) + railties (3.0.9) + actionpack (= 3.0.9) + activesupport (= 3.0.9) + rake (>= 0.8.7) + rdoc (~> 3.4) + thor (~> 0.14.4) + rake (0.9.2) + rdoc (3.8) + recaptcha (0.3.1) + redis (2.2.1) + redis-store (1.0.0.rc1) + redis (~> 2.2.0) + spectator-validates_email (0.0.7) + actionpack (~> 3.0.0) + activemodel (~> 3.0.0) + sqlite3 (1.3.3) + sqlite3 (1.3.3-x86-mingw32) + sqlite3-ruby (1.3.3) + sqlite3 (>= 1.3.3) + stalker (0.9.0) + beanstalk-client + json_pure + state_machine (1.0.1) + tabs_on_rails (2.0.2) + thor (0.14.6) + timecop (0.3.5) + treetop (1.4.9) + polyglot (>= 0.3.1) + tzinfo (0.3.29) + whenever (0.6.8) + aaronh-chronic (>= 0.3.9) + activesupport (>= 2.3.4) + will_paginate (3.0.pre2) + yui-compressor (0.9.6) + POpen4 (>= 0.1.4) + +PLATFORMS + ruby + x86-mingw32 + +DEPENDENCIES + activemerchant + authlogic + bartt-ssl_requirement + capistrano + carrierwave + daemon-spawn + factory_girl_rails + gibbon + haml + hoptoad_notifier + image_science! + jammit + jquery-rails + money + mysql2 (~> 0.2.7) + newrelic_rpm (>= 3.1.0) + rails (= 3.0.9) + recaptcha + redis + redis-store (>= 1.0.0.beta4) + spectator-validates_email + sqlite3-ruby + stalker + state_machine (>= 0.9.4) + tabs_on_rails (>= 1.3.1) + timecop + whenever + will_paginate (>= 3.0.pre2) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..56c847e --- /dev/null +++ b/LICENSE @@ -0,0 +1 @@ +This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/ or send a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA. \ No newline at end of file diff --git a/README b/README new file mode 100644 index 0000000..d024ea1 --- /dev/null +++ b/README @@ -0,0 +1,17 @@ +This is (nearly) all the code that powered FirstBargain.com until it was closed down. + +FirstBargain was a penny-auction startup formed by students at Cornell University, founded by Taichi Kasahara and Jing Hui Wang at Cornell University. The Ruby code you see here was written primarily by Caleb Perkins (www.calebperkins.org), also a student. The HAML templates and CSS were written by Jing. + +== Server requirements == +# Redis +# Beanstalkd +# Ruby 1.9.2 or better +# Rails 3 (3.1 or later not supported yet) + +Run as you would any Rails app. + +== Caveats == + +This code scaled well in production but there should be more test coverage. + +This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. See the LICENSE for more information. \ No newline at end of file diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..2017467 --- /dev/null +++ b/Rakefile @@ -0,0 +1,7 @@ +#!/usr/bin/env rake +# Add your own tasks in files placed in lib/tasks ending in .rake, +# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. + +require File.expand_path('../config/application', __FILE__) + +FirstBargain::Application.load_tasks diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb new file mode 100644 index 0000000..917770c --- /dev/null +++ b/app/controllers/accounts_controller.rb @@ -0,0 +1,68 @@ +class AccountsController < ApplicationController + ssl_required :new, :create, :edit, :update, :welcome + before_filter :require_user, only: [:show, :edit, :update, :welcome] + before_filter :require_no_user, only: [:new, :create] + set_tab :register, only: [:new, :create] + set_tab :overview, :sidebar, only: :show + set_tab :settings, :sidebar, only: [:edit, :update] + + def new + cookies[:referral] = {value: params[:u], expires: 1.week.from_now} if params[:u].present? + @account = Account.new + force_html @account do + render :layout => 'application' + end + end + + def create + @account = Account.new params[:account] + @account.registration_ip = request.remote_ip + [:affiliate, :referral, :utm_medium, :utm_source, :utm_campaign, :utm_term, :utm_content].each do |sym| + @account.public_send("#{sym}=", cookies[sym]) + end + force_html @account do + if @account.save + cookies.delete :referral + session[:welcome] = true + redirect_to welcome_account_url, notice: t("flash.account.created") + else render "create", :layout => 'application' + end + end + rescue ActiveRecord::RecordNotUnique # database hicupped, account was made + session[:welcome] = true + redirect_to welcome_account_url + rescue ActionController::InvalidAuthenticityToken + Rails.logger.warn "InvalidAuthenticityToken on registration page." + redirect_to new_account_url, alert: t("flash.session.expired_on_registration") + end + + def show + @winnings = current_user.winnings + @wins = current_user.wins_this_month.includes(:product) + @buynows = current_user.buynows.paginate(page: params[:page], per_page: 10) + respond_with current_user + end + + def edit + respond_with current_user + end + + def update + x = current_user.username + if current_user.update_attributes(params[:account]) then flash.notice = t("flash.account.updated") + else current_user.username = x + end + respond_with(current_user, location: account_url) + end + + def welcome + if session[:welcome] + @order = BidOrder.new + session.delete :welcome + cookies[:beginner] = 1 + render :layout => 'application' + else redirect_to bids_url(:secure => true) + end + end + +end diff --git a/app/controllers/activations_controller.rb b/app/controllers/activations_controller.rb new file mode 100644 index 0000000..a2c8d1f --- /dev/null +++ b/app/controllers/activations_controller.rb @@ -0,0 +1,23 @@ +class ActivationsController < ApplicationController + before_filter :require_user, only: :create + + def new + @account = Account.find_by_single_access_token params[:code] + if not @account then flash.alert = t("flash.activations.account_not_found") + elsif @account.verified? then flash.alert = t("flash.activations.already_verified") + else + @account.activate + flash.notice = t("flash.activations.activated") + end + redirect_to root_url + end + + def create + if current_user.verified? then redirect_to root_url, alert: t("flash.activations.already_verified") + else + current_user.deliver_activation_instructions + redirect_to account_path, notice: t("flash.activations.created") + end + end + +end diff --git a/app/controllers/addresses_controller.rb b/app/controllers/addresses_controller.rb new file mode 100644 index 0000000..db0ae48 --- /dev/null +++ b/app/controllers/addresses_controller.rb @@ -0,0 +1,28 @@ +class AddressesController < ApplicationController + before_filter :require_user + layout 'accounts' + set_tab :addresses, :sidebar + + def index + @addresses = current_user.addresses + end + + def new + @address = Address.new + end + + def create + @address = Address.new params[:address] + @address.account = current_user + if @address.save then redirect_to addresses_url, notice: t("flash.addresses.created") + else render "new" + end + end + + def destroy + @address = Address.find(params[:id]) + @address.destroy + redirect_to addresses_url, notice: t("flash.addresses.deleted") + end + +end diff --git a/app/controllers/admin/accounts_controller.rb b/app/controllers/admin/accounts_controller.rb new file mode 100644 index 0000000..b81a56f --- /dev/null +++ b/app/controllers/admin/accounts_controller.rb @@ -0,0 +1,56 @@ +class Admin::AccountsController < Admin::AdminController + cache_sweeper :account_sweeper, only: :adjust + + def index + respond_to do |wants| + wants.html {@accounts = Account.search(params[:s]).paginate :page => params[:page], :per_page => 50} + wants.xml {render :xml => Account.all} + end + end + + def show + @account = Account.find params[:id] + @orders = @account.orders.order('id DESC') + @bids = @account.bids.order('id ASC') + @invites = @account.children.order('id ASC') + @wins = @account.auctions.latest_ended.includes(:product) + respond_with [:admin, @account] + end + + def update + @account = Account.find params[:id] + @account.notes = params[:account][:notes] + @account.save + respond_with [:admin, @account] + end + + def adjust + @account = Account.find params[:id] + flash.notice = "Updated!" if @account.adjust(params[:account]) + respond_with [:admin, @account] + end + + def destroy + @account = Account.find params[:id] + @account.toggle! :active + respond_with [:admin, @account] + end + + def flag + @account = Account.find params[:id] + @account.toggle! :good_email + respond_with [:admin, @account] + end + + def subscribe + @account = Account.find params[:id] + @account.toggle! :subscribed + respond_with [:admin, @account] + end + + def online + @accounts = Account.where("last_request_at > ?", 10.minutes.ago).order("current_login_ip ASC") + respond_with [:admin, @accounts] + end + +end diff --git a/app/controllers/admin/admin_controller.rb b/app/controllers/admin/admin_controller.rb new file mode 100644 index 0000000..ed156e3 --- /dev/null +++ b/app/controllers/admin/admin_controller.rb @@ -0,0 +1,13 @@ +class Admin::AdminController < ApplicationController + + before_filter :require_admin if Rails.env.production? + layout 'admin' + respond_to :html, :js, :xml + + private + + def require_admin + redirect_to root_url unless current_user.try :admin? + end + +end \ No newline at end of file diff --git a/app/controllers/admin/analytics_controller.rb b/app/controllers/admin/analytics_controller.rb new file mode 100644 index 0000000..fa8935c --- /dev/null +++ b/app/controllers/admin/analytics_controller.rb @@ -0,0 +1,75 @@ +class Admin::AnalyticsController < Admin::AdminController + + @medium_opts = [:any, :cpc, :email, :cpm] + @source_opts = [:any, :google, :yahoo, :newsletter, :tv, :radio, :affiliate] + @campaign_opts = [:any] + @term_opts = [:any] + @content_opts = [:any] + + def index + @mediums = Set.new + @sources = Set.new + @campaigns = Set.new + @terms = Set.new + @contents = Set.new + Account.find_each do |a| + @mediums.add(a.utm_medium) if a.utm_medium + @sources.add(a.utm_source) if a.utm_source + @campaigns.add(a.utm_campaign) if a.utm_campaign + @terms.add(a.utm_term) if a.utm_term + @contents.add(a.utm_content) if a.utm_content + end + + from = DateTime.strptime("#{params[:start]} 00:00:00", "%m/%d/%Y %H:%M:%S") + 7.hours + to = DateTime.strptime("#{params[:end]} 23:59:59", "%m/%d/%Y %H:%M:%S") + 7.hours + @accounts = Account.where(:created_at => from..to) + @accounts = @accounts.where(:utm_medium => params[:medium]) if params[:medium] and params[:medium] != 'All Mediums' + @accounts = @accounts.where(:utm_source => params[:source]) if params[:source] and params[:source] != 'All Sources' + @accounts = @accounts.where(:utm_campaign => params[:campaign]) if params[:campaign] and params[:campaign] != 'All Campaigns' + @accounts = @accounts.where(:utm_term => params[:term]) if params[:term] and params[:term] != 'All Terms' + @accounts = @accounts.where(:utm_content => params[:content]) if params[:content] and params[:content] != 'All Content' + + data = [Hash.new(0), Hash.new(0), Hash.new(0)] + @accounts.each do |a| + d = a.created_at + data[2][d] += 1 + data[1][d] += 1 if a.cumulative_credits > 0 + total_revenue = 0 + a.orders.each do |o| + total_revenue += o.subtotal_in_cents if o.complete? + end + data[0][d] += total_revenue + end + keys = data[0].keys.sort + tdiff = keys[-1] - keys[0] unless keys.empty? + t_init = keys[0] + dt = 1.days + if tdiff > 2.months then + t_init = t_init.beginning_of_month + dt = 1.months + elsif tdiff > 2.years then + t_init = t_init.beginning_of_year + dt = 1.years + end + @graph_data = [Hash.new(0), Hash.new(0), Hash.new(0), Hash.new(0)] + keys.each do |k| + nk = case dt + when 1.days + k.beginning_of_day + when 1.months + k.beginning_of_month + when 1.years + k.beginning_of_year + end + @graph_data[0][nk] += data[0][k] + @graph_data[1][nk] += data[1][k] + @graph_data[2][nk] += data[2][k] + end + @graph_data[0].keys.each do |k| + @graph_data[3][k] = @graph_data[1][k] * 100.0 / @graph_data[2][k] + end + rescue + @graph_data = [{},{},{}] + end + +end diff --git a/app/controllers/admin/auctions_controller.rb b/app/controllers/admin/auctions_controller.rb new file mode 100644 index 0000000..e3cf2f4 --- /dev/null +++ b/app/controllers/admin/auctions_controller.rb @@ -0,0 +1,56 @@ +class Admin::AuctionsController < Admin::AdminController + + def index + respond_to do |wants| + wants.html do + @featured = FeaturedAuction.last + @active = Auction.active.descending.includes(:product).paginate :page => params[:active] + @finished = Auction.latest_ended.includes(:product).paginate :page => params[:finished] + end + wants.xml {render :xml => Auction.latest_ended.includes(:product)} + end + end + + def show + @auction = Auction.detailed.find params[:id] + @bids = @auction.bids.includes(:account) + end + + def new + @products = Product.where(discontinued: false).order('name ASC') + @auction = Auction.new + end + + def edit + @products = Product.order('name ASC') + @auction = Auction.find(params[:id]) + end + + def create + @auction = Auction.new(params[:auction]) + if @auction.save then redirect_to [:admin, @auction], notice: 'Auction was successfully created.' + else + @products = Product.order('name ASC') + render "new" + end + end + + def update + @auction = Auction.find(params[:id]) + if @auction.update_attributes(params[:auction]) then redirect_to [:admin, @auction], notice: 'Auction was successfully updated.' + else + @products = Product.order('name ASC') + render "edit" + end + end + + def destroy + @auction = Auction.find(params[:id]) + if @auction.bids.empty? then + @auction.destroy + redirect_to admin_auctions_url, notice: "Auction deleted." + else redirect_to admin_auctions_url, alert: "Auction has bids. Cannot delete." + end + end + +end diff --git a/app/controllers/admin/categories_controller.rb b/app/controllers/admin/categories_controller.rb new file mode 100644 index 0000000..ab7b157 --- /dev/null +++ b/app/controllers/admin/categories_controller.rb @@ -0,0 +1,28 @@ +class Admin::CategoriesController < Admin::AdminController + + def index + @category = Category.new + @categories = Category.all + end + + def new + @category = Category.new + end + + def edit + @category = Category.find params[:id] + end + + def update + @category = Category.find params[:id] + @category.update_attributes(params[:category]) + respond_with :admin, @category, location: admin_categories_url + end + + def create + @category = Category.new params[:category] + @category.save + respond_with :admin, @category, location: admin_categories_url + end + +end diff --git a/app/controllers/admin/coupons_controller.rb b/app/controllers/admin/coupons_controller.rb new file mode 100644 index 0000000..3826718 --- /dev/null +++ b/app/controllers/admin/coupons_controller.rb @@ -0,0 +1,17 @@ +class Admin::CouponsController < Admin::AdminController + + def index + @coupons = Coupon.all + end + + def new + @c = Coupon.new + end + + def create + @c = Coupon.new params[:coupon] + @c.save + respond_with @c, location: admin_coupons_url + end + +end diff --git a/app/controllers/admin/featured_auctions_controller.rb b/app/controllers/admin/featured_auctions_controller.rb new file mode 100644 index 0000000..778b19c --- /dev/null +++ b/app/controllers/admin/featured_auctions_controller.rb @@ -0,0 +1,49 @@ +class Admin::FeaturedAuctionsController < Admin::AdminController + + def index + redirect_to [:admin, :auctions] + end + + def show + @featured = FeaturedAuction.find params[:id] + @auction = Auction.find(@featured.auction_id) + end + + def edit + @featured = FeaturedAuction.find params[:id] + end + + def new + unless params[:auction_id] then + redirect_to [:admin, :auctions] + else + @auction = Auction.find(params[:auction_id]) + @featured = FeaturedAuction.new + end + end + + def create + @featured = FeaturedAuction.new(params[:featured_auction]) + @featured[:auction_id]=(params[:featured_auction][:auction_id]).to_i + if @featured.save then redirect_to [:admin, @featured], notice: 'Featured auction was successfully created.' + else + @auction = Auction.find(params[:featured_auction][:auction_id].to_i) + render "new" + end + end + + def update + @featured = FeaturedAuction.find(params[:id]) + if @featured.update_attributes(params[:auction]) then redirect_to [:admin, @featured], notice: 'Auction was successfully updated.' + else + render "edit" + end + end + + def destroy + @featured = FeaturedAuction.find params[:id] + @featured.destroy + redirect_to admin_auctions_url, notice: 'Auction deleted.' + end + +end \ No newline at end of file diff --git a/app/controllers/admin/orders_controller.rb b/app/controllers/admin/orders_controller.rb new file mode 100644 index 0000000..53e5a86 --- /dev/null +++ b/app/controllers/admin/orders_controller.rb @@ -0,0 +1,42 @@ +class Admin::OrdersController < Admin::AdminController + + def index + @orders = Order.search(params[:type], params[:s]).paginate :page => params[:page] + end + + def show + @order = Order.includes(:transactions, :account).find params[:id] + end + + def edit + @order = Order.find params[:id] + end + + def ship + @order = Order.find params[:id] + @order.confirmation = params[:order][:confirmation] + @order.tracking_id = params[:order][:tracking_id] + @order.shipping_company = params[:order][:shipping_company] + @order.ship! + redirect_to admin_orders_url, notice: "Shipped order #{@order.id}." + end + + def void + @order = Order.find params[:id] + @order.void! + redirect_to admin_orders_url, notice: "Voided order #{@order.id}." + end + + def approve + @order = Order.find params[:id] + @order.capture! + redirect_to admin_orders_url, notice: "Approved order #{@order.id}" + end + + def refund + @order = Order.find params[:id] + @order.refund! + redirect_to admin_orders_url, alert: "Refunded order #{@order.id}. Remember to adjust their bids as needed!" + end + +end diff --git a/app/controllers/admin/products_controller.rb b/app/controllers/admin/products_controller.rb new file mode 100644 index 0000000..bc9b6aa --- /dev/null +++ b/app/controllers/admin/products_controller.rb @@ -0,0 +1,49 @@ +class Admin::ProductsController < Admin::AdminController + cache_sweeper :product_sweeper + + def index + @active = Product.where(discontinued: false).order('products.name ASC') + @inactive = Product.where(discontinued: true).order('products.name ASC') + respond_with [@active, @inactive] + end + + def show + @product = Product.find(params[:id]) + respond_with @product + end + + def new + @categories = Category.order('categories.name ASC') + @product = Product.new + 4.times {@product.pictures.build} + respond_with @product + end + + def edit + @product = Product.find(params[:id]) + #(4 - @product.pictures.size).times {@product.pictures.build} + respond_with @product + end + + def create + @product = Product.new(params[:product]) + unless @product.save + @categories = Category.order('categories.name ASC') + (4 - @product.pictures.size).times {@product.pictures.build} + end + respond_with @product, location: [:admin, @product] + end + + def update + @product = Product.find(params[:id]) + @product.update_attributes(params[:product]) + respond_with @product, location: [:admin, @product] + end + + def destroy + @product = Product.find(params[:id]) + @product.destroy + respond_with @product + end + +end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb new file mode 100644 index 0000000..1b97116 --- /dev/null +++ b/app/controllers/application_controller.rb @@ -0,0 +1,95 @@ +# Where everything happens +class ApplicationController < ActionController::Base + include SslRequirement + protect_from_forgery + respond_to :html + helper_method :current_user, :logged_in?, :logged_out? + before_filter :require_vip if Rails.env.staging? + before_filter :set_utm_cookies, if: -> {params[:utm_source].present?} + rescue_from ActionController::InvalidAuthenticityToken, with: :rescue_invalid_token + + private + + def set_affiliate_cookies + [:affiliate, :categories, :affiliate_url].each do |sym| + cookies[sym] = {value: params[sym], expires: 1.week.from_now} if params[sym].present? + end + end + + def set_utm_cookies + [:utm_source, :utm_medium, :utm_campaign, :utm_term, :utm_content].each do |sym| + cookies[sym] = {value: params[sym], expires: 1.week.from_now} if params[sym].present? + end + end + + def rescue_invalid_token + store_location + redirect_to new_session_url, alert: t("flash.session.expired") + end + + def current_user_session + return @current_user_session if defined? @current_user_session + @current_user_session = AccountSession.find + end + + def current_user + return @current_user if defined? @current_user + @current_user = current_user_session.try :record + end + + def logged_in? + !!current_user + end + + def logged_out? + !current_user + end + + def vip + return @vip if defined? @vip + @vip = vip_session.try :record + end + + def vip_session + return @vip_session if defined? @vip_session + @vip_session = ViewerSession.find + end + + def require_user + if logged_out? + store_location + redirect_to new_session_url + end + end + + def require_no_user + if logged_in? + store_location + redirect_to account_url, alert: t("flash.session.must_be_logged_out") + end + end + + def store_location + session[:return_to] = request.get? ? request.fullpath : request.referer + end + + def redirect_back_or(default, options = {}) + path = (session[:return_to] || default) + session.delete :return_to + redirect_to path, options + end + + def require_vip + redirect_to splash_url unless vip + end + + # We need this because sometimes the http-accept on browsers is screwed up and they try requesting XML or something + def force_html(obj, options = {}) + respond_with obj, options do |format| + format.html do + yield + end + end + end + +end diff --git a/app/controllers/auctions_controller.rb b/app/controllers/auctions_controller.rb new file mode 100644 index 0000000..ad3c861 --- /dev/null +++ b/app/controllers/auctions_controller.rb @@ -0,0 +1,43 @@ +class AuctionsController < ApplicationController + set_tab :auctions, :except => :winners + set_tab :winners, only: :winners + before_filter :set_affiliate_cookies, only: :show + caches_action :winners, cache_path: :winners_cache, layout: false + + def index + @auctions = Auction.homepage(current_user, cookies[:categories]).paginate(page: params[:page], per_page: 16) + @featured = FeaturedAuction.last + @winners = Bid.winners(@auctions) + respond_with @auctions + end + + def show + @auction = Auction.find params[:id] + @product = @auction.product + @investment = @auction.investment_for current_user + @winner_investment = @auction.winner_investment + if logged_out? + @account = Account.new + else + @bot = BidBot.find_or_initialize_by_auction_id_and_account_id(@auction.id, current_user.id) + end + force_html @auctions do + if @auction.finished? then render "static" + else render "show" + end + end + end + + def winners + @auctions = Auction.history.in_categories(cookies[:categories]).paginate(page: params[:page], per_page: 15) + @winners = Bid.winners(@auctions) + respond_with @auctions + end + + private + + def winners_cache_url + "winners/#{Rails.cache.read('finished', raw: true)}/#{params[:page] || 1}" + end + +end diff --git a/app/controllers/bid_bots_controller.rb b/app/controllers/bid_bots_controller.rb new file mode 100644 index 0000000..9b126cb --- /dev/null +++ b/app/controllers/bid_bots_controller.rb @@ -0,0 +1,16 @@ +# TODO: make this RESTful +class BidBotsController < ApplicationController + before_filter :require_user + + def create + @auction = Auction.find(params[:auction_id]) + @bot = BidBot.find_or_initialize_by_account_id_and_auction_id(current_user.id, @auction.id) + if @bot.new_record? + @bot.attributes = params[:bid_bot] + @bot.save + else + @bot.destroy + end + end + +end diff --git a/app/controllers/bid_packs_controller.rb b/app/controllers/bid_packs_controller.rb new file mode 100644 index 0000000..2038c76 --- /dev/null +++ b/app/controllers/bid_packs_controller.rb @@ -0,0 +1,15 @@ +class BidPacksController < ApplicationController + set_tab :bids + ssl_exceptions + before_filter :require_user + + def new + @order = BidOrder.new + force_html @order do + if current_user.has_purchased? then render "new" + else render "first" + end + end + end + +end diff --git a/app/controllers/bids_controller.rb b/app/controllers/bids_controller.rb new file mode 100644 index 0000000..34193f9 --- /dev/null +++ b/app/controllers/bids_controller.rb @@ -0,0 +1,24 @@ +class BidsController < ApplicationController + before_filter :require_user + respond_to :js + #respond_to :html, :except => :create + + def create + @auction = Auction.find params[:auction_id] + @bid = Bid.create :account => current_user, :auction => @auction + current_user.decrement(@bid.paid ? :credits : :bonuses) if @bid.persisted? # avoid current_user.reload + respond_with(@auction, @bid, location: @auction) do |wants| + wants.js do + if @bid.errors.empty? then render 'success' + elsif @bid.errors[:investment].any? then render 'buynow' + else render 'failure' + end + end + wants.html do + @bid.errors.empty? ? flash.notice = t("flash.bids.without_xhr") : flash.alert = @bid.errors.full_messages[0] + redirect_to @auction + end + end + end + +end diff --git a/app/controllers/bookmarks_controller.rb b/app/controllers/bookmarks_controller.rb new file mode 100644 index 0000000..3450be5 --- /dev/null +++ b/app/controllers/bookmarks_controller.rb @@ -0,0 +1,24 @@ +class BookmarksController < ApplicationController + before_filter :require_user + layout "accounts" + set_tab :watchlist, :sidebar + respond_to :js, only: :destroy + + def index + @watchlist = current_user.watched_auctions.order 'bookmarks.created_at DESC' + respond_with @watchlist + end + + def create + @auction = Auction.find params[:auction_id] + @bookmark = Bookmark.find_or_create_by_account_id_and_auction_id current_user.id, @auction.id + respond_with @bookmark, location: bookmarks_url + end + + def destroy + @auction = Auction.find params[:id] + @bookmark = Bookmark.find_by_auction_id_and_account_id! @auction.id, current_user.id + @bookmark.destroy + respond_with @bookmark, location: bookmarks_url + end +end diff --git a/app/controllers/ccbill_controller.rb b/app/controllers/ccbill_controller.rb new file mode 100644 index 0000000..96ceda6 --- /dev/null +++ b/app/controllers/ccbill_controller.rb @@ -0,0 +1,15 @@ +class CcbillController < ActionController::Metal + + def create + o = Order.from_ccbill(params) + if o.save + Rails.cache.delete_matched("homepage/*/#{o.account_id}") # OPTIMIZE: pessimistic cache expiration + response = o.process_postback(params) + o.process_response response + else Rails.logger.warn "CCBill postback at #{Time.current} not saved: #{params.inspect}" + end + self.content_type = Mime::TEXT + self.response_body = params.inspect + end + +end \ No newline at end of file diff --git a/app/controllers/contacts_controller.rb b/app/controllers/contacts_controller.rb new file mode 100644 index 0000000..5092cac --- /dev/null +++ b/app/controllers/contacts_controller.rb @@ -0,0 +1,21 @@ +class ContactsController < ApplicationController + layout 'static' + set_tab :contact, :sidebar + set_tab :contact + + def show + @contact = Contact.new + respond_with @contact + end + + def create + @contact = Contact.new(params[:contact]) + force_html @contact, location: root_url do + if verify_recaptcha(model: @contact, private_key: Rails.configuration.recaptcha_private) && @contact.save + redirect_to root_url, notice: t("flash.contact.created") + else render "show" + end + end + end + +end diff --git a/app/controllers/coupons_controller.rb b/app/controllers/coupons_controller.rb new file mode 100644 index 0000000..a8f60b7 --- /dev/null +++ b/app/controllers/coupons_controller.rb @@ -0,0 +1,18 @@ +class CouponsController < ApplicationController + before_filter :require_user + layout 'accounts' + set_tab :coupons, :sidebar + + def new + @c = CouponUse.new + respond_with @c + end + + def create + @c = CouponUse.new params[:coupon_use] + @c.account = current_user + flash.notice = t("flash.coupons.created", count: @c.bonuses) if @c.save + respond_with @c, location: account_url + end + +end diff --git a/app/controllers/invitations_controller.rb b/app/controllers/invitations_controller.rb new file mode 100644 index 0000000..41e7080 --- /dev/null +++ b/app/controllers/invitations_controller.rb @@ -0,0 +1,20 @@ +class InvitationsController < ApplicationController + layout 'accounts' + before_filter :require_user + set_tab :invitations, :sidebar + + def index + @invitation = Invitation.new current_user + respond_with @invitation + end + + def create + @invitation = Invitation.new current_user, params[:invitation] + force_html @invitation do + if @invitation.save then redirect_to invitations_url, notice: t("flash.invitations.created") + else render 'index' + end + end + end + +end diff --git a/app/controllers/landings_controller.rb b/app/controllers/landings_controller.rb new file mode 100644 index 0000000..2ac56c5 --- /dev/null +++ b/app/controllers/landings_controller.rb @@ -0,0 +1,42 @@ +class LandingsController < ApplicationController + def show + @auction = Auction.where(:product_id => params[:id]).current_or_previous + if @auction.present? + @product = @auction.product + @winner_investment = @auction.winner_investment + @investment = @auction.investment_for current_user + @account = current_user ? current_user : Account.new + force_html @auction do + render(@auction.active? ? :active : :finished) + end + else redirect_to root_url + end + end + + def promo + reject = [1,12,13,14,15,28,29] + cats = (1..40).reject {|c| (reject.include? c)} + @auctions = Auction.homepage(current_user, cats)[0..7] + @account = Account.new + force_html @auctions do + render "promo", :layout => nil + end + end + + def category + @auction = Auction.in_categories(params[:id]).current_or_previous + if @auction.present? + @product = @auction.product + @winner_investment = @auction.winner_investment + @investment = @auction.investment_for current_user + @account = current_user ? current_user : Account.new + @upcoming = Auction.ending_soonest.includes(:product).limit(4) + @ended = Auction.inactive.order("products.widget_worthy DESC", "auctions.ending_at ASC").includes(:product).limit(4) + force_html @auction do + render :category + end + else redirect_to root_url + end + end + +end diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb new file mode 100644 index 0000000..9282ab1 --- /dev/null +++ b/app/controllers/orders_controller.rb @@ -0,0 +1,72 @@ +class OrdersController < ApplicationController + before_filter :require_user + before_filter :require_order, only: [:paypal, :create] + set_tab :orders, :sidebar + ssl_exceptions + cache_sweeper :account_sweeper, only: :create + + def index + @orders = current_user.orders.order('orders.id DESC') + force_html @orders do + render :layout => 'accounts' + end + end + + def new + @order = factory(params, false) + respond_with @order + end + + def confirm + session[:order] = params[:order] + factory params[:order] + force_html @order do + if @order.invalid? && @order.is_a?(BidOrder) then render('bid_packs/new', layout: 'application') + elsif @order.invalid? then render 'new' + elsif @order.paypal? then redirect_to @order.paypal_url(paypal_orders_url(secure: true), root_url) + else redirect_to @order.ccbill_url # render "confirm" + end + end + end + + def create + factory session[:order] + session.delete :order + if @order.save + flash[:order_id] = @order.id + @order.process_paypal_purchase! + end + end + + def paypal + session[:order][:express_token] = params[:token] + factory session[:order] + session[:order] = @order.to_user_session + respond_with @order + end + + def success + @order = Order.find(flash[:order_id]) + if @order.is_a?(BidOrder) and not @order.account.bids_purchased + session[:bidpopup] = 1 + @order.account.update_attribute(:bids_purchased, true) + end + @msg = @order.transactions.first.message + respond_with @order + end + + def failure + success # the only difference is the template loaded + end + + private + + def require_order + redirect_to root_url, alert: t("flash.session.expired_order") unless session[:order] + end + + def factory(source, set_attr = true) + @order = Order.factory(source, current_user, request.remote_ip, set_attr) + end + +end diff --git a/app/controllers/password_resets_controller.rb b/app/controllers/password_resets_controller.rb new file mode 100644 index 0000000..aefe17c --- /dev/null +++ b/app/controllers/password_resets_controller.rb @@ -0,0 +1,36 @@ +class PasswordResetsController < ApplicationController + before_filter :require_no_user + before_filter :load_user, only: [:edit, :update] + + def new + respond_with + end + + def edit + respond_with + end + + def update + flash.notice = t("flash.password_reset.success") if @account.update_attributes(params[:account]) + respond_with @account, location: root_url + end + + def create + @account = Account.find_by_email params[:email] + if @account + @account.deliver_password_reset_instructions + redirect_to root_url, notice: t("flash.password_reset.sent") + else + flash.now.alert = t("flash.password_reset.no_account") + render "new" + end + end + + private + + def load_user + @account = Account.find_using_perishable_token params[:code], 1.week + redirect_to(root_url, alert: t("flash.password_reset.expired")) unless @account + end + +end diff --git a/app/controllers/poller_controller.rb b/app/controllers/poller_controller.rb new file mode 100644 index 0000000..97b4581 --- /dev/null +++ b/app/controllers/poller_controller.rb @@ -0,0 +1,37 @@ +# Handles all XHR auction updates. +class PollerController < ActionController::Metal + + def show + offset + a = Auction.find(params[:id]) + u = Account.find_by_single_access_token(params[:u]) + self.response_body = Rails.cache.fetch([a, u]) do + a.as_detailed(u).to_json + end + self.content_type = Mime::JSON + rescue + self.status = :bad_request + end + + def index + offset + u = Account.find_by_single_access_token(params[:u]) + self.response_body = Rails.cache.fetch(["homepage", Rails.cache.read('bids', raw: true), Rails.cache.read('finished', raw: true), params[:ids], u]) do + ids = params[:ids].split('-') + Auction.summaries(u, ids).to_json + end + self.content_type = Mime::JSON + rescue + self.status = :bad_request + end + + private + + # Expects a UTC timestamp in milliseconds. Returns time offset in milliseconds and original timestamp. + def offset + headers["NTP-Offset"] = (Time.now.to_f*1000 - params[:t].to_i).to_s + headers["NTP-Time"] = params[:t] + headers["Cache-Control"] = "no-cache, must-revalidate" + end + +end \ No newline at end of file diff --git a/app/controllers/products_controller.rb b/app/controllers/products_controller.rb new file mode 100644 index 0000000..7e49fed --- /dev/null +++ b/app/controllers/products_controller.rb @@ -0,0 +1,26 @@ +class ProductsController < ApplicationController + set_tab :store + caches_action :index, cache_path: :index_cache, layout: false + caches_action :show, cache_path: :show_cache, layout: false + + def index + @products = Product.store.paginate(page: params[:page], per_page: 12) + respond_with @products + end + + def show + @product = Product.store.find(params[:id]) + respond_with @product + end + + private + + def index_cache_url + "member-shop/index/#{params[:page] || 1}/#{logged_in? ? current_user.points.cents : 'none'}" + end + + def show_cache_url + "member-shop/show/#{params[:id]}/#{logged_in? ? current_user.points.cents : 'none'}" + end + +end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb new file mode 100644 index 0000000..ee31a58 --- /dev/null +++ b/app/controllers/sessions_controller.rb @@ -0,0 +1,28 @@ +class SessionsController < ApplicationController + before_filter :require_no_user, only: [:new, :create] + before_filter :require_user, only: :destroy + ssl_required :new, :create + ssl_allowed :destroy + + def new + @session = AccountSession.new + respond_with @session + end + + def create + @session = AccountSession.new params[:account_session] + force_html @session do + if @session.save then redirect_back_or root_url(:beginner => @session.record.beginner?) + else render "new" + end + end + end + + def destroy + current_user_session.destroy + reset_session + flash.notice = t("flash.session.deleted") + respond_with current_user_session, location: new_session_url + end + +end diff --git a/app/controllers/splashes_controller.rb b/app/controllers/splashes_controller.rb new file mode 100644 index 0000000..4130a2b --- /dev/null +++ b/app/controllers/splashes_controller.rb @@ -0,0 +1,20 @@ +class SplashesController < ApplicationController + skip_before_filter :require_vip + layout nil +# ssl_exceptions + + def show + @a = ViewerSession.new + respond_with @a + end + + def create + @a = ViewerSession.new params[:viewer_session] + force_html @a do + if @a.save then redirect_to auctions_url + else render "show" + end + end + end + +end diff --git a/app/controllers/static_controller.rb b/app/controllers/static_controller.rb new file mode 100644 index 0000000..3fe16eb --- /dev/null +++ b/app/controllers/static_controller.rb @@ -0,0 +1,92 @@ +class StaticController < ApplicationController + + set_tab :faq + set_tab :tutorial, only: %w(tutorial rewards guarantee tips) + set_tab :faq, :sidebar, only: %w(faq_new_user faq_auctions faq_account faq_shipping faq_payment faq about) + set_tab :about, :sidebar, only: :about + set_tab :rules, :sidebar, only: :rules + set_tab :tos, :sidebar, only: :tos + set_tab :privacy, :sidebar, only: :privacy + set_tab :returns, :sidebar, only: :sidebar + set_tab :play, :sidebar, only: :tutorial + set_tab :rewards, :sidebar, only: :rewards + set_tab :guarantee, :sidebar, only: :guarantee + layout :choose_layout + + caches_action :faq_new_user, :faq_auctions, :faq_account, :faq_shipping, :faq_payment, :faq, :about, :rules, :tos, :privacy, :returns, :tutorial, :rewards, :guarantee, :tips, :layout => false + + def faq_new_user + render "faq_new_user.html" + end + + def faq_auctions + render "faq_auctions.html" + end + + def faq_account + render "faq_account.html" + end + + def faq_shipping + render "faq_shipping.html" + end + + def faq_payment + render "faq_payment.html" + end + + def faq + render "faq.html" + end + + def about + render "about.html" + end + + def rules + render "rules.html" + end + + def tos + render "tos.html" + end + + def privacy + render "privacy.html" + end + + def returns + render "returns.html" + end + + def tutorial + render "tutorial.html" + end + + def rewards + render "rewards.html" + end + + def guarantee + render "guarantee.html" + end + + def tips + render "tips.html" + end + + private + + def choose_layout + return "basic" if params[:popup].present? + case action_name + when "tutorial", "rewards", "guarantee" + "howtoplay" + when "tips" + "application" + else + "static" + end + end + +end diff --git a/app/controllers/widget_controller.rb b/app/controllers/widget_controller.rb new file mode 100644 index 0000000..33a5291 --- /dev/null +++ b/app/controllers/widget_controller.rb @@ -0,0 +1,26 @@ +# Handles widget initialization and updates. +class WidgetController < ActionController::Metal + + def show + t, data = Rails.cache.fetch("auction/-#{params[:id]}-/promo") do + a = Auction.find(params[:id]) + [a.ending_at, a.serializable_hash] + end + data[:no] = (Time.now.to_f*1000 - params[:t].to_i) + data[:nt] = params[:t] + Rails.cache.delete("auction/-#{params[:id]}-/promo") if t.past? + self.response_body = "#{params[:callback]}(#{data.to_json})" + self.content_type = Mime::JS + rescue + self.status = :bad_request + end + + def index + p = Auction.widgety(params[:widgets], params[:auctions]).map! {|a| a.as_product(request)}.to_json + self.response_body = "#{params[:callback]}(#{p})" + self.content_type = Mime::JS + rescue + self.status = :bad_request + end + +end \ No newline at end of file diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb new file mode 100644 index 0000000..f924c05 --- /dev/null +++ b/app/helpers/application_helper.rb @@ -0,0 +1,51 @@ +module ApplicationHelper + + def yield_for(sym, default) + content_for?(sym) ? content_for(sym) : default + end + + def user_login + current_user.try(:username).to_json + end + + def user_id + current_user.try(:single_access_token).to_json + end + + def captcha + recaptcha_tags(:display => {:theme => 'clean'}, :public_key => Rails.configuration.recaptcha_public).html_safe + end + + def supported_browser? + (request.user_agent =~ /MSIE (6|5)/).nil? + end + + def load_affiliate_stylesheet + include_stylesheets(cookies[:affiliate].to_sym) if cookies[:affiliate].present? + rescue Jammit::PackageNotFound + end + + def link_to_affiliate + url = if request.ssl? || cookies[:affiliate_url].blank? then root_path + else cookies[:affiliate_url] + end + link_to "First Bargain", url + end + + def pagination(collection) + will_paginate collection, :previous_label => "« Previous", :next_label => "Next »" + end + + def fill_grid(collection, kind, per_row) + n = per_row - collection.size.modulo(per_row) + return if n == per_row + x = "" + n.times do |i| + x << if i == n - 1 then "" + else "" + end + end + x.html_safe + end + +end diff --git a/app/helpers/auctions_helper.rb b/app/helpers/auctions_helper.rb new file mode 100644 index 0000000..25d1d9f --- /dev/null +++ b/app/helpers/auctions_helper.rb @@ -0,0 +1,46 @@ +module AuctionsHelper + + def fb_share_auction_description(auction) + "#{auction.product.name} going at #{number_to_currency auction.going_price} and will end in #{time_ago_in_words auction.ending_at}. Bid now and save big!" + end + + def auction_ids(*auctions) + auctions.flatten.map {|a| a.id}.to_json + end + + def auction_classes(a) + classes = ["price-#{a.price_increment_in_cents}", "timer-#{a.timer_reset}"] + classes << if a.finished? then "ended-trigger" + elsif a.beginner? then "beginner" + elsif a.hot then "hot" + end + end + + def auction_prices(*auctions) + p = {} + auctions.flatten.each {|a| p[a.id] = a.retail_price.to_f} + p.to_json + end + + def facebook_share_auction(auction) + p = {:u => auction_url(auction), :t => "Great deal on #{auction.product.name}"} + link_to "Share", "http://www.facebook.com/sharer.php?#{p.to_query}", :name => "fb_share", :type => "button_count" + end + + def bidder(u, add_you = false) + u == current_user.try(:username) ? "#{u}#{" (You!)" if add_you}".html_safe : u + end + + def increment_title(a) + "Each bid raises the auction price by #{number_to_currency a.price_increment}" + end + + def timer_title(a) + "When the clock is under #{a.timer_reset} seconds, each bid will reset the clock to #{a.timer_reset} seconds" + end + + def picture_url(a) + request.protocol + request.host_with_port + a.product.main_picture.url + end + +end diff --git a/app/helpers/orders_helper.rb b/app/helpers/orders_helper.rb new file mode 100644 index 0000000..61b2d54 --- /dev/null +++ b/app/helpers/orders_helper.rb @@ -0,0 +1,74 @@ +module OrdersHelper + + def hide_card_number(card_number) + card_number.sub /(\S){12}/, "XXXX-XXXX-XXXX-" + end + + def kind(o) + return params[:kind] if params[:kind].present? + case o.type + when "AuctionOrder" then "auction" + when "BuyNowOrder" then "buynow" + when "RewardOrder" then "reward" + else "bidpack" + end + end + + def buyable(o) + params[:buyable].blank? ? o.buyable_id : params[:buyable] + end + + def price_title(o) + case o.type + when "AuctionOrder" then "Auction Price" + when "BuyNowOrder" then "BuyNow Price" + else "Regular Price" + end + end + + def order_picture(o) + pic = case o.type + when "AuctionOrder", "BuyNowOrder" then o.auction.product.main_picture.url :medium + when "BidOrder" then "bidpacks/#{o.buyable_id}-bids.jpg" + when "RewardOrder" then o.product.main_picture.url :medium + end + image_tag(pic, size: "280x260") + end + + def order_contents_title(o) + path = case o.type + when "AuctionOrder" then "Auction Won" + when "BuyNowOrder" then "Buy Now" + when "BidOrder" then "Bid Pack" + when "RewardOrder" then "Members Shop" + end + end + + def order_contents_link(o) + path = case o.type + when "AuctionOrder", "BuyNowOrder" then auction_path(o.auction) + when "BidOrder" then bids_path + when "RewardOrder" then product_path(o.product) + end + link_to o.contents, path + end + + def link_to_order(o) + case o.type + when "AuctionOrder" then link_to o.contents, auction_path(o.auction) + when "BuyNowOrder" then link_to o.contents, auction_path(o.auction), :class => "auction-buy-now" + when "BidOrder" then o.contents + when "RewardOrder" then content_tag(:span, o.contents, :class => "membershop-purchase") + end + end + + def order_class(o) + case o.type + when "AuctionOrder" then "auction-win" + when "BuyNowOrder" then "auction-buy-now" + when "BidOrder" then "bid-pack-purchase" + when "RewardOrder" then "membershop-purchase" + end + end + +end diff --git a/app/helpers/products_helper.rb b/app/helpers/products_helper.rb new file mode 100644 index 0000000..d16046e --- /dev/null +++ b/app/helpers/products_helper.rb @@ -0,0 +1,28 @@ +module ProductsHelper + + def display_percentage(p) + f = p.display_discount(current_user).to_f/p.retail_price.to_f*100 + number_to_percentage [f.floor, 0].max, :precision => 0 + end + + def buy_now_percentage(i, a) + f = (1-(i.amount_in_cents + a.going_price_in_cents)/a.retail_price_in_cents.to_f)*100 + number_to_percentage [f.floor, 0].max, :precision => 0 + end + + # Takes order or product + def shipping_price(p) + p.shipping_price.zero? ? "Free!" : number_to_currency(p.shipping_price) + end + + def facebook_share_product(p) + link_to image_tag("icons/facebook.png", size: "32x32"), "http://www.facebook.com/sharer.php?u=#{product_url p}&t=#{p.name}" + end + + def return_policy(p) + if [12,13,14,15,28,29].include?(p.category_id) then "Gift cards are not eligible for returns" + else "Return within 14 days for any reason" + end + end + +end diff --git a/app/mailers/customer_mailer.rb b/app/mailers/customer_mailer.rb new file mode 100644 index 0000000..9fae5fc --- /dev/null +++ b/app/mailers/customer_mailer.rb @@ -0,0 +1,45 @@ +class CustomerMailer < ActionMailer::Base + default :from => "FirstBargain.com " + layout "notifier", :except => :invitation + + + def won_auction(auction_id) + @auction = Auction.find auction_id + @account = @auction.winning_bid.account + mail :to => @account.email, :subject => "You Won: #{@auction.product.name}", :"X-SMTPAPI" => '{"category": "Win Notification"}' + end + + def forgot_password(account_id) + @account = Account.find account_id + mail :to => @account.email, :"X-SMTPAPI" => '{"category": "Password Reset"}' + end + + def activation_instructions(account_id) + @account = Account.find account_id + mail :to => @account.email, :subject => "Verify Email Address", :"X-SMTPAPI" => '{"category": "Account Activation"}' + end + + def welcome(account_id) + @account = Account.find account_id + mail :to => @account.email, :subject => "Welcome to FirstBargain",:"X-SMTPAPI" => '{"category": "Account Welcome"}' + end + + def order_confirmation(order_id) + @order = Order.find order_id + @account = @order.account + mail :to => @account.email, :"X-SMTPAPI" => '{"category": "Order Confirmation"}' + end + + def shipment_confirmation(order_id) + @order = Order.find order_id + @account = @order.account + mail :to => @account.email, :"X-SMTPAPI" => '{"category": "Shipping Confirmation"}' + end + + def invitation(json) + hash = JSON.parse json + @message = hash["message"] + mail :bcc => hash["addresses"], :subject => "#{hash["name"]} grabbed you an invitation to FirstBargain.com", :"X-SMTPAPI" => '{"category": "Invite"}', :from => "FirstBargain " + end + +end diff --git a/app/mailers/staff_mailer.rb b/app/mailers/staff_mailer.rb new file mode 100644 index 0000000..2d9aec0 --- /dev/null +++ b/app/mailers/staff_mailer.rb @@ -0,0 +1,36 @@ +class StaffMailer < ActionMailer::Base + default :from => "FirstBargain " + + def inquiry(hash) + @contact = Contact.new(hash) + mail :to => "FirstBargain Support ", :subject => @contact.subject, :"X-SMTPAPI" => '{"category": "Contact Form"}' + end + + def daily_activity_report + @now = Time.current.beginning_of_day + @since = @now - 1.day + @bidpacks = BidOrder.good_between(@since, @now) + @auctions = AuctionOrder.good_between(@since, @now) + @buynows = BuyNowOrder.good_between(@since, @now) + @rewards = RewardOrder.good_between(@since, @now) + @accounts = Account.member_between(@since,@now) + # Affiliates + @a_signups = @accounts.group(:source).size + @a_bid_count = @bidpacks.joins(:account).group("accounts.source").size + @a_bid_value = @bidpacks.joins(:account).group("accounts.source").revenue + mail :from => "FirstBargain Daily Report ", :to => ["taichi@firstbargain.com", "jing@firstbargain.com", "corporate@expedientshopping.com"], :"X-SMTPAPI" => '{"category": "Finance Reports"}' + end + + def weekly_activity_report + @now = Time.current.beginning_of_day + @since = @now - 1.week + @new_signups = Account.member_between(@since,@now).size + b = BidOrder.good_between(@since, @now).includes(:account) + @new_purchasers = b.where("accounts.created_at > ?", @since).distinct_purchasers + @old_purchasers = b.where("accounts.created_at < ?", @since).distinct_purchasers + @new_bid_revenue = b.where("accounts.created_at > ?", @since).revenue + @old_bid_revenue = b.where("accounts.created_at < ?", @since).revenue + mail :from => "FirstBargain Weekly Report ", :to => ["taichi@firstbargain.com", "jing@firstbargain.com", "corporate@expedientshopping.com"], :"X-SMTPAPI" => '{"category": "Finance Reports"}' + end + +end diff --git a/app/models/account.rb b/app/models/account.rb new file mode 100644 index 0000000..e88deeb --- /dev/null +++ b/app/models/account.rb @@ -0,0 +1,214 @@ +class Account < ActiveRecord::Base + + acts_as_authentic do |c| + c.validate_email_field false + c.validates_length_of_login_field_options within: 3..14, if: :username_changed? + c.validates_format_of_login_field_options with: /\A[a-zA-Z0-9]+$/, if: :username_changed? + end + + belongs_to :parent, class_name: "Account" + has_many :children, class_name: "Account", foreign_key: "parent_id" + has_many :bids, inverse_of: :account + has_many :auctions, inverse_of: :account + has_many :bookmarks, inverse_of: :account, dependent: :destroy + has_many :orders, inverse_of: :account + has_many :investments, inverse_of: :account + has_many :watched_auctions, through: :bookmarks, source: :auction + has_many :bid_auctions, through: :investments, source: :auction + has_many :addresses, inverse_of: :account, dependent: :destroy + has_many :bid_bots, inverse_of: :account, dependent: :destroy + + scope :member_between, ->(from, to) {where(created_at: from..to)} + + money :points + attr_accessor :terms_of_service + attr_reader :points_increment, :credits_increment, :bonuses_increment + attr_accessible :username, :email, :password, :password_confirmation, :terms_of_service, :birth_date, :referral, :source, :subscribed + alias_attribute :affiliate, :source + + validates :email, email: {mx: false}, format: {without: Rails.configuration.banned_domains}, uniqueness: {case_sensitive: false}, if: :email_changed? + validates :terms_of_service, acceptance: true + validates :points, :bonuses, :credits, numericality: {greater_than_or_equal_to: 0} + validate :legal_adult, if: :birth_date_changed? + validate :limit_username_change, if: :username_changed? + validate(:check_ip, on: :create) if Rails.env.production? + + after_create :deliver_welcome_and_verification + after_validation :set_last_change, if: :username_changed? + + SEARCHABLE = %w(username email registration_ip current_login_ip last_login_ip source).map! {|a| "accounts.#{a} LIKE ?"}.freeze + + def self.search(q) + if q.present? then where([SEARCHABLE.join(" OR ")] + SEARCHABLE.map {q}) + else scoped + end.order('accounts.id DESC') + end + + # Active auctions being bid on + def active_auctions + Auction.active.joins(:investments).where(investments: {account_id: id}) + end + + # Bots participating in active auctions + def active_bots + bid_bots.joins(:auction).where("auctions.ending_at > ?", Time.now) + end + + def referral=(a) + self.parent = self.class.find_by_username(a) if a.present? + end + + def referral + parent.username if parent_id? + end + + def referral_link + "https://www.firstbargain.com/account/new?u=#{username}" + end + + def make_first_purchase + return if has_purchased + self.has_purchased = true + parent.award(:bonuses, Rails.configuration.referral_bonus).save! if parent_id + save! + end + + def total_bids + credits + bonuses + end + + def has_bids? + total_bids > 0 + end + + # How much has the user spent on our site? + def total_spent + @spent ||= orders.good.reduce(0.to_money) {|spent, order| spent + order.total_price} + end + + # How much has the user's wins cost us? + def total_cost + @value ||= orders.where('type != "BidOrder"').good.reduce(0.to_money) do |value, order| + value + order.product.cost + end + end + + def profit_and_loss + total_spent - total_cost + end + + def poller_hash + {c: credits, b: bonuses} + end + + def beginner? + reload.auctions.inactive.blank? + end + + def already_won?(auction) + wins_this_month.where(product_id: auction.product_id).present? + end + + def wins_left_this_month + [Rails.configuration.monthly_win_limit - wins_this_month.size, 0].max + end + + def wins_left_today + [Rails.configuration.daily_win_limit - wins_today.size, 0].max + end + + def winnings + auctions.winnables.descending.nonredeemed.detailed + end + + def wins_this_month + auctions.finished_this_month + end + + def wins_this_week + t = Time.current + auctions.where(ending_at: (t - 1.week)..t) + end + + def wins_today + t = Time.current + auctions.where(ending_at: t.beginning_of_day..t) + end + + # Keep in sync with Auction::can_buy_now? + def buynows + bid_auctions.inactive.where("investments.expired" => false). + where("auctions.account_id <> ?", id).buynowables. + detailed.order('investments.updated_at DESC') + end + + def deliver_password_reset_instructions + reset_perishable_token! + Stalker.enqueue("emails.customer", {method: :forgot_password, params: id}) + end + + def admin? + Rails.configuration.admins.include? id + end + + def activate + raise "Account #{id} is already verified" if verified + toggle(:verified) + award(:bonuses, Rails.configuration.subscription_bonus) if subscribed? + save! + end + + def adjust(a) + award(:credits, a[:credits_increment]) + award(:bonuses, a[:bonuses_increment]) + self.points += a[:points_increment].to_money + save + end + + def deliver_activation_instructions + Stalker.enqueue("emails.customer", {method: :activation_instructions, params: id}) + end + + # Convenience setter to set cumulative bids and normal bids. Use this only when the cumulative counter should be increased too. + def award(kind, n = 1) + n = n.to_i + self[kind] += n + self["cumulative_#{kind}".to_sym] += n + self + end + + def self.sync_mailchimp + g = Gibbon::API.new("7657cdcddee2100d5498b5920f5383a6-us2", cid: "5d4c9b54b1") + records = g.campaignAbuseReports["data"] + g.campaignMembers(status: "soft")["data"] + g.campaignMembers(status: "hard")["data"] + records.map! {|r| r["email"]} + where(email: records).update_all(good_email: false) + where(email: g.campaignUnsubscribes["data"]).update_all(subscribed: false) + end + + private + + def deliver_welcome_and_verification + Stalker.enqueue("emails.customer", {method: :welcome, params: id}) + deliver_activation_instructions + end + + def limit_username_change + errors.add(:username, :limited) if last_username_change && last_username_change > 1.month.ago + end + + def set_last_change + self.last_username_change = Time.now + end + + def check_ip + if Account.where(registration_ip: registration_ip).present? && Approval.without?(registration_ip) + logger.warn "REGISTRATION FAILED - (#{username}, #{registration_ip})" + errors.add(:base, :ip_taken) + end + end + + def legal_adult + errors.add(:birth_date) if birth_date > 18.years.ago.to_date + end + +end diff --git a/app/models/account_session.rb b/app/models/account_session.rb new file mode 100644 index 0000000..5047055 --- /dev/null +++ b/app/models/account_session.rb @@ -0,0 +1,3 @@ +class AccountSession < Authlogic::Session::Base + self.last_request_at_threshold = 1.minute +end \ No newline at end of file diff --git a/app/models/address.rb b/app/models/address.rb new file mode 100644 index 0000000..7be4714 --- /dev/null +++ b/app/models/address.rb @@ -0,0 +1,18 @@ +class Address < ActiveRecord::Base + belongs_to :account, inverse_of: :addresses + validates :account_id, :name, :label, :address, :city, :state, :presence => true + validates :phone, :zip, numericality: true + attr_accessible :name, :address, :address_2, :city, :state, :zip, :country, :phone, :label + before_validation :fix_phone + + STATES = ['AK', 'AL', 'AR', 'AZ', 'CA', 'CO', 'CT', 'DC', 'DE', 'FL', 'GA', 'HI', 'IA', 'ID', + 'IL', 'IN', 'KS', 'KY', 'LA', 'MA', 'MD', 'ME','MI','MN','MO','MS','MT','NC','ND','NE','NH', + 'NJ','NM','NV','NY','OH','OK','OR','PA','RI','SC','SD','TN','TX','UT','VA','VT','WA','WI','WV', 'WY'].freeze + + private + + def fix_phone + phone.gsub! /-/, "" + end + +end diff --git a/app/models/approval.rb b/app/models/approval.rb new file mode 100644 index 0000000..05581ce --- /dev/null +++ b/app/models/approval.rb @@ -0,0 +1,17 @@ +class Approval < ActiveRecord::Base + after_commit :clear_cache + + def self.without?(ip) + ips = Rails.cache.fetch("approved-ips") do + all.collect(&:ip) + end + not ips.include?(ip) + end + + private + + def clear_cache + Rails.cache.delete("approved-ips") + end + +end diff --git a/app/models/auction.rb b/app/models/auction.rb new file mode 100644 index 0000000..951d737 --- /dev/null +++ b/app/models/auction.rb @@ -0,0 +1,259 @@ +class Auction < ActiveRecord::Base + + money :price_increment + money :going_price + money :retail_price + attr_accessible :product_id, :ending_at, :price_increment, :hot, :is_buy_now, :timer_reset, :beginner + after_create :set_watchers + + belongs_to :product, inverse_of: :auctions + belongs_to :account, inverse_of: :auctions + belongs_to :investment, inverse_of: :auction + has_many :bids, inverse_of: :auction, :dependent => :destroy + has_many :investments, inverse_of: :auction, :dependent => :destroy + has_many :bid_bots, inverse_of: :auction, :dependent => :destroy + has_one :featured_auction + + scope :active, -> { where("auctions.ending_at > ?", Time.now) } + scope :inactive, -> { where("auctions.ending_at <= ?", Time.now) } + scope :ascending, order('auctions.ending_at ASC') + scope :descending, order('auctions.ending_at DESC') + scope :ending_soonest, -> {active.ascending} + scope :latest_ended, -> {inactive.descending} + scope :hot, where(:hot => true) + scope :nonredeemed, where(redeemed: false) + scope :nonbeginner, where(beginner: false) + + scope :detailed, includes(:product) + scope :upcoming, -> { hot.where('auctions.ending_at > ?', 1.day.from_now.beginning_of_day).ascending } + scope :finished_this_month, -> {t = Time.current; where(:ending_at => t.beginning_of_month..t).ascending} + scope :finished_in_last_24_hours, -> {t = Time.current; where(:ending_at => (t - 1.days)..t).ascending} + scope :history, -> {where(:ending_at => 3.days.ago..Time.now).nonbeginner.descending.includes(:product, :investment)} + + validates :product_id, :ending_at, :retail_price, :presence => true + validates :redeemed, :hot, :is_buy_now, :inclusion => [true, false] + validates :price_increment, numericality: {:greater_than => 0} + validates :going_price, numericality: {greater_than_or_equal_to: 0} + validate :in_future, on: :create + + def self.expire_redis_job_cache_for_last_24_hours + Auction.finished_in_last_24_hours.each do |a| + a.expire_job_cache + end + end + + def self.buynowables + where(is_buy_now: true).where("auctions.ending_at > ?", Time.current - Rails.configuration.buy_now_expiration) + end + + def self.winnables + t = Time.current + t0 = t - Rails.configuration.won_auction_expiration + where(ending_at: t0..t) + end + + def self.widgety(w_c, a_c) + w_c = w_c.split("-") + a_c = a_c.split("-") + active.detailed.where("products.category_id" => w_c + a_c).order("products.widget_worthy DESC", "auctions.ending_at ASC").limit(5) + end + + def recent_bids + @recent_bids ||= bids.recent.to_a + end + + def self.current_or_previous + ending_soonest.first or latest_ended.first + end + + # Filter beginner auctions + def self.for_user(u) + if u && u.beginner? then scoped + else nonbeginner + end + end + + def self.in_categories(c) + if c.present? + d = if c.is_a?(String) then c.split("-") # don't use respond_to? + else c + end + detailed.where("products.category_id" => d) + else scoped + end + end + + def product_id=(pid) + self[:product_id] = pid + self.retail_price = product.retail_price + end + + def active? + !finished + end + + def winning_bid + recent_bids.first + end + + def username(cache = nil) + if cache then cache[id].try(:username) || "none" + else winning_bid.try(:username) || "none" + end + end + + def self.homepage(user, categories) + a = hot.latest_ended.limit(1) + a + for_user(user).active.order('hot DESC, ending_at ASC').in_categories(categories) + end + + def ending_in=(t) + self.ending_at = t.from_now + end + + def won_by?(user) + user && user.id == account_id && finished? + end + + def redemption_expired? + (ending_at + Rails.configuration.won_auction_expiration).past? + end + + def bids_count + going_price.cents/price_increment.cents + end + + def total_buy_now_price(u) + product.shipping_price + buy_now_price(u) + end + + def total_won_price + product.shipping_price + going_price + end + + def total_winner_price + going_price + winner_investment.amount + end + + def can_buy_now?(user) + is_buy_now and not won_by?(user) and (ending_at + Rails.configuration.buy_now_expiration).future? and not bought_by?(user) + end + + # Optimize me + def winner_investment(cache = nil) + @w ||= account_id ? investment : Investment.new + #@w ||= if cache then cache[id] || Investment.new + #else winning_bid.present? ? winning_bid.investment : Investment.new + #end + end + + def investment_for(user) + @i ||= user ? Investment.find_or_initialize_by_account_id_and_auction_id(user.id, id) : Investment.new + end + + def bought_by?(user) + investment_for(user).expired + end + + # MSRP - (# of bids placed on THIS auction * price of bids) + def buy_now_price(user) + return retail_price unless user + inv = investment_for user + return retail_price if inv.expired + [retail_price - inv.amount, 0.to_money].max + end + + def serializable_hash(cache = nil) + record = {:id => id, :p => going_price.to_f, :u => username(cache), :e => ending_at.to_i} + record[:w] = winner_investment.serializable_hash + record[:wp] = total_winner_price.to_f + record[:done] = finished? + record + end + + def winner_savings_ratio + 1 - total_winner_price.to_f/retail_price.to_f + end + + def as_product(request) + data = serializable_hash + data[:name] = product.name + data[:retail_price] = retail_price.to_f + data[:picture] = "#{request.protocol}#{request.host_with_port}#{product.main_picture.url(:index)}" + # Get previous auction + a2 = Auction.latest_ended.where(:product_id => product_id).first + if a2 + data[:prev_winner] = a2.username + data[:prev_price] = a2.total_winner_price.to_f + data[:prev_savings] = "#{[(a2.winner_savings_ratio*100).floor.round, 0].max}%" + end + data + end + + def as_summary(winners_cache = nil, investment_cache = nil) + data = serializable_hash(winners_cache) + data[:investment] = investment_cache[id].try(:serializable_hash) if investment_cache + data + end + + def self.summaries(user, ids) + auctions = Auction.includes(:investment).find(ids) + winners = Bid.winners(auctions) + investments = Investment.by_auction(ids, user) + hash = {} + if user + hash[:account] = user.poller_hash + end + hash[:auctions] = auctions.map! {|r| r.as_summary(winners, investments)} + hash + end + + def as_detailed(u) + data = serializable_hash + if u + i = investments.find_by_account_id(u.id) + data[:investment] = i.serializable_hash if i + bot = bid_bots.find_by_account_id(u.id) + data[:bot] = bot.bids_left if bot + data[:account] = u.poller_hash + end + data[:bids] = recent_bids.each_with_index.map do |b, i| + b.serializable_hash(going_price - price_increment * i) + end + data[:n] = bids_count + data + end + + def to_param + "#{id}-#{product.name.parameterize}" + end + + def <=>(a) + ending_at <=> a.ending_at + end + + def expensive? + retail_price >= Rails.configuration.price_threshold + end + + def cache_key + "auctions/#{id}-#{going_price_in_cents}-#{finished}" + end + + def expire_job_cache + $redis.expire("auction_#{id}_job_ids", 0) + end + + private + + # Bid bot and email winners jobs + def set_watchers + Stalker.enqueue("emails.won_auction", {id: id}, {delay: (ending_at - Time.now).round + 30}) + BidBot.enqueue(self) + end + + def in_future + errors.add(:ending_at, :past) if ending_at.past? + end + +end diff --git a/app/models/auction_order.rb b/app/models/auction_order.rb new file mode 100644 index 0000000..5ef4dfa --- /dev/null +++ b/app/models/auction_order.rb @@ -0,0 +1,57 @@ +# An order for an auction a user has won. To be created, it must be nonredeemed and won by that user. +class AuctionOrder < Order + + belongs_to :auction, :foreign_key => :buyable_id + validate :validate_item, on: :create + delegate :product, :retail_price, to: :auction + + def contents + product.name + end + + def auction=(a) + self.buyable_id = a.id + self.subtotal = a.going_price + self.shipping_price = a.product.shipping_price + self.point_discount = 0 + end + + def requires_shipping? + product.requires_shipping + end + + def bid_pack? + product.bonuses > 0 + end + + def kind + "auction" + end + + def self.cogs + Money.new(joins(:auction => :product).sum(:cost_in_cents).to_i) + end + + protected + + def validate_item + error = if not auction.won_by?(account) then :did_not_win + elsif auction.redeemed then :already_redeemed + elsif auction.redemption_expired? then :expired + end + errors.add(:base, error) if error + end + + def finish_purchase + account.award(:bonuses, auction.product.bonuses).save! + end + + def complete_reset + auction.update_attribute(:redeemed, false) + end + + def setup_purchase + auction.update_attribute(:redeemed, true) + end + +end \ No newline at end of file diff --git a/app/models/bid.rb b/app/models/bid.rb new file mode 100644 index 0000000..b8ad2f1 --- /dev/null +++ b/app/models/bid.rb @@ -0,0 +1,111 @@ +class Bid < ActiveRecord::Base + + belongs_to :account, inverse_of: :bids + belongs_to :auction, inverse_of: :bids + + validates :account_id, :auction_id, :username, presence: true + validates :paid, inclusion: [true, false] + validate :goodness, on: :create + + attr_accessible :auction_id, :auction, :account, :account_id + + scope :recent, order('bids.id DESC').limit(10) + + after_create :expire_redis_bidbot_set, :update_account, :update_investment, :update_auction, :enqueue_bid_bot_job + after_commit :increment_cache + + # Bottleneck. Refer to "max n per group" problem, or + # http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/ + def self.winners(auctions) + auction_ids = auctions.map {|a| a.id} + query = "select * from (select auction_id, max(id) as maxid from bids where auction_id in(?) group by auction_id) as x inner join bids as b on b.auction_id = x.auction_id and b.id = x.maxid" + records = find_by_sql [query, auction_ids] + records.index_by {|r| r.auction_id} + # Old, slower: + # records = where(:auction_id => auction_ids).where("id = (select max(id) from bids as b where b.auction_id = bids.auction_id)") + end + + def serializable_hash(price) + {u: username, t: created_at.to_s(:bid), p: price.to_f} + end + + def price(counter) + auction.going_price - auction.price_increment * counter + end + + def investment + @investment ||= Investment.find_or_initialize_by_account_id_and_auction_id(account_id, auction_id) + end + + def account=(u) + self.account_id = u.id + self.username = u.username + self.paid = u.bonuses < 1 + end + + private + + def goodness + error = first_time_bidding if investment.new_record? + error ||= if investment.expired? then :buy_now_used + elsif auction.ending_at.past? then :auction_ended + elsif not account.has_bids? then :need_more_bids + elsif account_id == auction.recent_bids.first.try(:account_id) then :bid_twice + end + errors.add(:base, error) if error.present? + errors.add(:investment, :overinvested) if paid && auction.is_buy_now && overinvested? + end + + def first_time_bidding + t = Time.current + wins = account.wins_this_month.to_a + y = [Rails.configuration.monthly_win_limit - wins.size, 0].max + x = [Rails.configuration.daily_win_limit - wins.count {|a| a.ending_at > t.beginning_of_day && a.ending_at < t}, 0].max # (t.beginning_of_day..t).include?(a.ending_at) no good, bug? + z = account.active_auctions.to_a + if y.zero? then :monthly_win_limit_reached + elsif x.zero? then :daily_win_limit_reached + elsif y <= z.size then :monthly_active_auctions_limit + elsif x <= z.size then :daily_active_auctions_limit + elsif auction.expensive? && (wins+z).any? {|a| a.product_id == auction.product_id} then :item_too_expensive + elsif auction.beginner && z.any? {|a| a.beginner?} then :beginner_limit + elsif auction.beginner && !account.beginner? then :not_beginner + end + end + + def overinvested? + auction.going_price + investment.amount + Rails.configuration.bid_unit_price > auction.retail_price + end + + # Update the time, investment, and user id as atomically as possible. + def update_auction + x = Time.current + auction.timer_reset.seconds + time = auction.ending_at < x ? x : auction.ending_at + updates = ["going_price_in_cents = going_price_in_cents + price_increment_in_cents, account_id = ?, investment_id = ?, ending_at = ?", account.id, investment.id, time] + Auction.update_all(updates, id: auction.id) + end + + def update_account + account.decrement(paid ? :credits : :bonuses).save! + end + + def update_investment + if paid then investment.increment(:credits_used).increment(:amount_in_cents, Rails.configuration.bid_unit_price.cents) + else investment.increment(:bonuses_used) + end.save! + end + + def increment_cache + Rails.cache.increment("bids") + end + + def expire_redis_bidbot_set + $redis.expire("auction_#{auction.id}_job_ids", 0) + true + end + + def enqueue_bid_bot_job + BidBot.enqueue(auction.reload) + true + end + +end diff --git a/app/models/bid_bot.rb b/app/models/bid_bot.rb new file mode 100644 index 0000000..3f8e46b --- /dev/null +++ b/app/models/bid_bot.rb @@ -0,0 +1,86 @@ +# Bids on an auction on a user's behalf. Every few seconds before an auction ends, the system will query all registered bots for the auction and update one of them. +class BidBot < ActiveRecord::Base + money :bid_from + belongs_to :auction, inverse_of: :bid_bots + belongs_to :account + + #validates :auction_id, :uniqueness => {:scope => :account_id} + validates :bid_from, numericality: {greater_than_or_equal_to: 0} + validates :bids_left, numericality: {greater_than_or_equal_to: 0}, on: :update + validate :number_of_bids, on: :create + validate :active_bots, on: :create + + attr_protected :account_id, :auction_id + + after_create :create_investment + after_destroy :remove_investment_if_unused + + + def self.enqueue(a) + unless a.finished? + Stalker.enqueue("bid_bot", {id: a.id, redis_job_id: $redis.incr("last_bid_bot_job_id")}, {delay: bidbot_bid_delay(a)}) + $redis.sadd("auction_#{a.id}_job_ids", $redis.get("last_bid_bot_job_id")) + end + end + + def bid! + b = Bid.new(:account => account, :auction => auction) + b.botted = true + decrement(:bids_left).save if b.save # TODO: transactions + b.persisted? + end + + private + + #Returns a delay time for stalker based on a probability distribution + def self.bidbot_bid_delay(a) + r = (rand * 100).floor + case(r) + when 0..14 then offset_seconds = (4 + r) + when 15..24 then offset_seconds = 3 + when 25..49 then offset_seconds = 2 + when 50..99 then offset_seconds = 1 + end + Rails.logger.debug "Rand #{offset_seconds}" + calculate_delay_from_offset(a, offset_seconds) + end + + def self.calculate_delay_from_offset(a, offset) + ((a.ending_at - Time.now).floor - offset) + end + + + # Get an okay bound on good bots for an auction. We still might need to try some bots to see if they can bid. + # TODO: caching. Also, move this into Auction model? + # If you update this query be sure the appropriate database indexes are in place + def self.pool(a) + bots = a.reload.bid_bots + bots = bots.where("bid_bots.account_id <> ?", a.account_id) if a.account_id? + bots = bots.where("bid_bots.bids_left > ?", 0).where("bid_bots.bid_from_in_cents <= ?", a.going_price.cents) + bots.shuffle! # bots.order(configurations[Rails.env]['adapter'] == "sqlite3" ? "random()" : "rand()") + end + + def number_of_bids + errors.add(:bids_left, :not_in_range) unless (3..50).include?(bids_left) + errors.add(:bids_left, :need_more_bids) if account.total_bids < bids_left.to_i + b = Bid.new(:account => account, :auction => auction) + errors.add(:base, b.errors.full_messages.first) if b.invalid? + end + + # If this bot is destroyed but not used yet, destroy the investment to clear an active auctions site + def remove_investment_if_unused + i = auction.investment_for(account) + i.destroy if i.bids_used.zero? + end + + # Create a placeholder investment to take up an active auction slot + def create_investment + i = auction.investment_for(account) + i.save! if i.new_record? + end + + def active_bots + errors.add(:base, :active_bot_limit) if account.active_bots.size >= 1 + end + +end diff --git a/app/models/bid_order.rb b/app/models/bid_order.rb new file mode 100644 index 0000000..b33e71e --- /dev/null +++ b/app/models/bid_order.rb @@ -0,0 +1,38 @@ +class BidOrder < Order + alias_attribute :quantity, :buyable_id + alias_attribute :retail_price, :subtotal + + validates :quantity, inclusion: {in: [30, 50, 100, 200], message: "is not valid"}, on: :create + + def quantity=(q) + self.buyable_id = q.to_i + self.subtotal = Rails.configuration.bid_unit_price * q.to_i + self.shipping_price = 0 + self.point_discount = 0 + end + + def requires_shipping? + false + end + + def bid_pack? + true + end + + def contents + "Bid pack (#{quantity})" + end + + def kind + "bidpack" + end + + protected + + def finish_purchase + account.award(:credits, quantity) + account.points += subtotal + account.save! + end + +end \ No newline at end of file diff --git a/app/models/bookmark.rb b/app/models/bookmark.rb new file mode 100644 index 0000000..a54da81 --- /dev/null +++ b/app/models/bookmark.rb @@ -0,0 +1,10 @@ +# A bookmarked auction on the user's watchlist. +class Bookmark < ActiveRecord::Base + + belongs_to :account, inverse_of: :bookmarks + belongs_to :auction + + validates :auction_id, :presence => true, :uniqueness => {:scope => :account_id} + validates :account_id, :presence => true + +end diff --git a/app/models/buy_now_order.rb b/app/models/buy_now_order.rb new file mode 100644 index 0000000..8565857 --- /dev/null +++ b/app/models/buy_now_order.rb @@ -0,0 +1,46 @@ +class BuyNowOrder < Order + belongs_to :auction, :foreign_key => :buyable_id + validate :validate_item, on: :create + delegate :retail_price, :product, to: :auction + delegate :requires_shipping?, to: :product + + def contents + product.name + end + + def auction=(a) + self.buyable_id = a.id + self.subtotal = a.buy_now_price(account) + self.shipping_price = a.product.shipping_price + self.point_discount = 0 + self.sales_tax = a.product.tax + end + + def bid_pack? + product.bonuses > 0 + end + + def kind + "buynow" + end + + def self.cogs + Money.new(joins(:auction => :product).sum(:cost_in_cents).to_i) + end + + protected + + def validate_item + errors.add(:auction, :invalid) unless auction.can_buy_now?(account) + #errors.add(:subtotal, "is not correct") if subtotal < auction.buy_now_price(account) + end + + def finish_purchase + account.award(:bonuses, auction.product.bonuses).save! + end + + def setup_purchase + auction.investment_for(account).expire! + end + +end \ No newline at end of file diff --git a/app/models/category.rb b/app/models/category.rb new file mode 100644 index 0000000..cd87f8f --- /dev/null +++ b/app/models/category.rb @@ -0,0 +1,4 @@ +class Category < ActiveRecord::Base + has_many :products, :dependent => :restrict + validates :name, :presence => true +end diff --git a/app/models/contact.rb b/app/models/contact.rb new file mode 100644 index 0000000..d6821dc --- /dev/null +++ b/app/models/contact.rb @@ -0,0 +1,29 @@ +class Contact + include ActiveModel::Validations + include ActiveModel::Conversion + include ActiveModel::MassAssignmentSecurity + extend ActiveModel::Naming + + attr_accessor :email, :subject, :message + attr_accessible :email, :subject, :message + + validates :email, format: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, presence: true + validates :subject, :message, presence: true + + def initialize(attributes = {}) + sanitize_for_mass_assignment(attributes).each { |name, value| public_send("#{name}=", value) } + end + + def persisted? + false + end + + def save + if valid? + Stalker.enqueue("emails.contact_form", as_json) + true + else false + end + end + +end diff --git a/app/models/coupon.rb b/app/models/coupon.rb new file mode 100644 index 0000000..6c8af5a --- /dev/null +++ b/app/models/coupon.rb @@ -0,0 +1,12 @@ +# Leave uses left nil to be unlimited. +class Coupon < ActiveRecord::Base + + validates :code, :summary, :ends_at, :presence => true + validates :bonuses, numericality: {:greater_than => 0} + validates :uses_left, numericality: {greater_than_or_equal_to: 0, :allow_blank => true} + + def expired? + ends_at.past? || uses_left.try(:<=, 0) + end + +end diff --git a/app/models/coupon_use.rb b/app/models/coupon_use.rb new file mode 100644 index 0000000..81b1b16 --- /dev/null +++ b/app/models/coupon_use.rb @@ -0,0 +1,26 @@ +class CouponUse < ActiveRecord::Base + belongs_to :account + belongs_to :coupon + attr_reader :code + delegate :bonuses, to: :coupon + validates :account_id, presence: true + validates :coupon_id, presence: true, uniqueness: {scope: :account_id} + validate :expiration, if: :coupon_id? + after_create :give_bids + + def code=(c) + self.coupon = Coupon.find_by_code c + end + + private + + def give_bids + account.award(:bonuses, bonuses).save! + coupon.decrement(:uses_left).save! if coupon.uses_left? + end + + def expiration + errors.add(:coupon_id, "has expired") if coupon.expired? + end + +end diff --git a/app/models/featured_auction.rb b/app/models/featured_auction.rb new file mode 100644 index 0000000..aaab50c --- /dev/null +++ b/app/models/featured_auction.rb @@ -0,0 +1,5 @@ +class FeaturedAuction < ActiveRecord::Base + attr_accessible :name, :description, :image_url + belongs_to :auction + validates :auction_id, :name, presence: true +end diff --git a/app/models/investment.rb b/app/models/investment.rb new file mode 100644 index 0000000..8abcc11 --- /dev/null +++ b/app/models/investment.rb @@ -0,0 +1,44 @@ +# How much a user has spent on an auction, enabling custom buy-now prices. +class Investment < ActiveRecord::Base + money :amount + belongs_to :account, inverse_of: :investments + belongs_to :auction, inverse_of: :investments + + validates :account_id, :auction_id, presence: true + validates :amount, :credits_used, :bonuses_used, numericality: {greater_than_or_equal_to: 0} + validates :expired, inclusion: [true, false] + + scope :nonexpired, where(expired: false) + + # Expire all buy now prices older than 24 hours + def self.perform + nonexpired.where("updated_at <= ?", Rails.configuration.buy_now_expiration.ago).update_all(expired: true) + end + + def self.by_auction(auction_ids, user) + where(account_id: user.try(:id), auction_id: auction_ids).index_by(&:auction_id) + end + + def expire! + self.expired = true + save! + end + + def unexpire! + self.expired = false + save! + end + + def bids_used + bonuses_used + credits_used + end + + def buynow_price + [auction.retail_price - amount, 0.to_money].max + end + + def serializable_hash(options = nil) + {a: amount.to_f, c: credits_used, b: bonuses_used} + end + +end diff --git a/app/models/invitation.rb b/app/models/invitation.rb new file mode 100644 index 0000000..2e8c6c8 --- /dev/null +++ b/app/models/invitation.rb @@ -0,0 +1,54 @@ +class Invitation + include ActiveModel::Validations + include ActiveModel::Conversion + extend ActiveModel::Naming + include ActiveModel::MassAssignmentSecurity + + attr_accessor :name, :sender + attr_reader :emails + + attr_accessor_with_default :addresses, [] + + attr_accessor_with_default :message do + "Hey,\n\nI'd like to invite you to First Bargain, a members-only auction site where you can walk away with unheard of deals on today's hottest gadgets and designer products.\n\nMembership is free, so join me today on FirstBargain.com to start saving big on all the brands you love!\n\n#{sender.referral_link}" + end + + attr_protected :sender, :addresses + + validate :check_emails + validates :message, :name, :sender, presence: true + + def initialize(s, attributes = {}) + sanitize_for_mass_assignment(attributes).each {|name, value| public_send("#{name}=", value)} + self.sender = s + end + + def emails=(a) + @emails = a + self.addresses = a.split(',').each {|e| e.strip!} + end + + def persisted? + false + end + + def save + if valid? + Stalker.enqueue("emails.customer", {method: :invitation, params: as_json}) + true + else false + end + end + + def as_json(options = nil) + {message: message, addresses: addresses, name: name} + end + + private + + def check_emails + errors.add(:emails, :length) unless (1..5) === addresses.size + errors.add(:emails, :invalid) unless addresses.all? {|e| e =~ Authlogic::Regex.email} + end + +end diff --git a/app/models/order.rb b/app/models/order.rb new file mode 100644 index 0000000..de67846 --- /dev/null +++ b/app/models/order.rb @@ -0,0 +1,183 @@ +require 'ccbill' +require 'paypal' + +# = Making a CCBill purchase +# * User goes through OrdersController and gets redirected to CCBill. CCBill redirects them to their orders page. +# * In background: +# ** CCBill sends a postback to CCBillController +# ** CCBillController calls: process_postback -> process_response +# = Making a PayPal purchase +class Order < ActiveRecord::Base + include CCBill + extend CCBill::ClassMethods + include PayPal + + US_STATES = %w[AK AL AR AZ CA CO CT DC DE FL GA HI IA ID IL IN KS KY LA MA MD ME MI MN MO MS MT NC ND NE NH NJ NM NV NY OH OK OR PA RI SC SD TN TX UT VA VT WA WI WV WY].freeze + + money :shipping_price + money :point_discount + money :subtotal + money :sales_tax + has_many :transactions, :dependent => :destroy, inverse_of: :order + belongs_to :account, inverse_of: :orders + attr_accessor :different_shipping, :gateway, :kind, :buyable + attr_protected :shipping_price, :point_discount, :subtotal + + validates :account_id, :buyable_id, :presence => true + validates :shipping_address, :shipping_address_2, if: -> {requires_shipping? and paypal?}, on: :create, format: {without: /\b[P|p]*(OST|ost)*\.*\s*[O|o|0]*(ffice|FFICE)*\.*\s*[B|b][O|o|0][X|x]\b/, message: "cannot be a PO Box, sorry"} + + state_machine :initial => :unsaved do + event :capture do + transition [:unsaved, :pending] => :paid, :if => :requires_shipping? + transition [:unsaved, :pending] => :complete + end + event :capture_later do + transition :unsaved => :pending + end + event :decline do + transition [:unsaved, :pending] => :declined + end + event :review do + transition [:unsaved, :pending] => :under_review + end + event :approve do + transition :under_review => :paid, :if => :requires_shipping? + transition :under_review => :complete + end + event :ship do + transition :paid => :shipped + end + event :void do + transition [:under_review, :paid, :complete, :shipped] => :void + end + event :refund do + transition [:paid, :complete, :shipped] => :refunded + end + after_transition :from => :unsaved, on: [:capture, :review], :do => :single_step_purchase + after_transition :from => :pending, on: [:capture, :review], :do => :finish_purchase + before_transition on: :ship, :do => :complete_shipment + after_transition :from => :pending, :to => :declined, :do => :complete_reset + after_transition on: :capture_later, :do => :setup_purchase + end + + scope :good, without_state(:declined, :void, :refunded) + scope :good_between, ->(from,to) {good.where("orders.created_at" => from..to)} + + STATES = state_machine.states.map {|s| [s.human_name, s.name]}.freeze + SEARCHABLE = ["accounts.username", "orders.id"].map {|a| "#{a} LIKE ?"}.freeze + MINIMUM_CHARGE = 2.95.to_money.freeze + + def self.search(state = nil, string = nil) + state = :unsaved unless state.present? # state may be a string + x = with_state(state.to_sym).order('orders.id DESC') + if string.present? then x.joins(:account).where([SEARCHABLE.join(" OR ")] + SEARCHABLE.map {string}) + else x.includes(:account) + end + end + + def self.factory(source, user, ip = nil, set_attr = true) + source.to_options! + b = source[:buyable] || source[:quantity] || source[:buyable_id] + o = case source[:kind] + when "auction" then AuctionOrder.new :account => user, :auction => Auction.find(b) + when "buynow" then BuyNowOrder.new :account => user, :auction => Auction.find(b) + when "reward" then RewardOrder.new :account => user, :product => Product.find(b) + else BidOrder.new :account => user, :quantity => b + end + o.ip_address = ip + o.attributes = source if set_attr + o + end + + def self.revenue + result = sum("subtotal_in_cents + shipping_price_in_cents + sales_tax_in_cents - point_discount_in_cents") + if result.is_a?(Hash) then result.each_with_object({}) {|(k,v), acc| acc[k] = Money.new(v.to_i)} + else Money.new(result.to_i) + end + end + + def self.distinct_purchasers + select("DISTINCT orders.account_id").size + end + + def process_response(response) + transactions.create! :action => "purchase", :amount => total_price, :response => response + if response.fraud_review? + account.make_first_purchase + send_confirmation + review! + elsif response.success? + account.make_first_purchase + send_confirmation + capture! + else decline! + end + end + + # Send remote order fulfillment request to CCBill + def self.perform(order_id) + o = find(order_id) + o.create_fulfillment! if o.requires_shipping? + end + + def total_price + [subtotal + sales_tax + shipping_price - point_discount, MINIMUM_CHARGE].max + end + + def kind + raise NotImplementedError + end + + def contents + raise NotImplementedError + end + + def billing_name + "#{first_name} #{last_name}" + end + + def requires_shipping? + true + end + + def bid_pack? + false + end + + def to_user_session + x = as_json :except => [:created_at, :confirmation, :shipped_at, :point_discount_in_cents, :card_type, :updated_at, :tracking_id, :subtotal_in_cents, :shipping_company, :shipping_price_in_cents, :account_id, :sales_tax_in_cents, :card_expires_on, :state, :ip_address] + x["kind"] = kind + x + end + + private + + def send_confirmation + Stalker.enqueue("emails.customer", {method: :order_confirmation, params: id}) if paypal? && account.good_email? + end + + def complete_shipment + self.shipped_at = Time.now + Stalker.enqueue("emails.customer", {method: :shipment_confirmation, params: id}) + Stalker.enqueue("Order", {order_id: id}) if tracking_id.present? && tracking_id_changed? + end + + def single_step_purchase + setup_purchase + finish_purchase + end + + protected + + def complete_reset + end + + # Part one of a two-step purchase. Should be used to prevent user from redeeming twice, et cetera. + def setup_purchase + end + + # Part two of a two-step purchase. Should be used to reward user with bids, et cetera. + def finish_purchase + end + +end diff --git a/app/models/picture.rb b/app/models/picture.rb new file mode 100644 index 0000000..143d5d3 --- /dev/null +++ b/app/models/picture.rb @@ -0,0 +1,6 @@ +# A picture for a product. +class Picture < ActiveRecord::Base + belongs_to :product, inverse_of: :pictures + validates :data, :presence => true + mount_uploader :data, ProductImageUploader +end diff --git a/app/models/product.rb b/app/models/product.rb new file mode 100644 index 0000000..c28c676 --- /dev/null +++ b/app/models/product.rb @@ -0,0 +1,52 @@ +# A product that may be sold directly or auctioned off. +class Product < ActiveRecord::Base + money :retail_price + money :shipping_price + money :max_discount + money :tax + money :cost + + mount_uploader :main_picture, MainPictureUploader + + has_many :auctions, inverse_of: :product, :dependent => :restrict + has_many :pictures, inverse_of: :product, :dependent => :destroy + belongs_to :category, inverse_of: :products + accepts_nested_attributes_for :pictures, :allow_destroy => true, :reject_if => proc { |attributes| attributes['data'].blank? } + + validates :name, :summary, :description, :category_id, :main_picture, :presence => true + validates :visible, :requires_shipping, :inclusion => [true, false] + validates :retail_price, numericality: {:greater_than => 0} + validates :shipping_price, :cost, :max_discount, :bonuses, :tax, numericality: {greater_than_or_equal_to: 0} + + scope :store, where(visible: true, discontinued: false).order('products.id DESC') + + def point_discount(user) + user ? [user.points, max_discount].min : 0.to_money + end + + # MSRP - (# of member points up to x% of MSRP) + def reward_price(user) + retail_price - point_discount(user) + end + + def display_price(user) + retail_price - display_discount(user) + end + + def display_discount(user) + user ? [max_discount, user.points].min : max_discount + end + + def to_param + "#{id}-#{name.parameterize}" + end + + def bid_pack? + category_id == 1 + end + + def cog + retail_price - bonuses * Rails.configuration.bid_unit_price + end + +end diff --git a/app/models/reward_order.rb b/app/models/reward_order.rb new file mode 100644 index 0000000..c2f35d0 --- /dev/null +++ b/app/models/reward_order.rb @@ -0,0 +1,42 @@ +class RewardOrder < Order + belongs_to :product, :foreign_key => :buyable_id + validate :validate_item, on: :create + delegate :retail_price, :requires_shipping?, to: :product + + def contents + product.name + end + + def product=(p) + self.buyable_id = p.id + self.subtotal = p.retail_price + self.shipping_price = p.shipping_price + self.point_discount = p.point_discount(account) + self.sales_tax = p.tax + end + + def kind + "reward" + end + + def self.cogs + Money.new(joins(:product).sum(:cost_in_cents).to_i) + end + + protected + + def validate_item + errors.add(:point_discount, :invalid) if point_discount > product.point_discount(account) + end + + def setup_purchase + account.points -= point_discount + account.save! + end + + def complete_reset + account.points += point_discount + account.save! + end + +end \ No newline at end of file diff --git a/app/models/transaction.rb b/app/models/transaction.rb new file mode 100644 index 0000000..5709667 --- /dev/null +++ b/app/models/transaction.rb @@ -0,0 +1,26 @@ +class Transaction < ActiveRecord::Base + money :amount + belongs_to :order, inverse_of: :transactions + serialize :params + + validates :order_id, :amount, :message, :presence => true + validates :success, :inclusion => [true, false] + validates :action, :inclusion => %w(purchase refund) + + def response=(response) + self.success = response.success? + self.authorization = response.authorization + self.message = response.message + self.params = response.params + rescue ActiveMerchant::ActiveMerchantError => e + self.success = false + self.authorization = nil + self.message = e.message + self.params = {} + end + + def processor + params["transaction_type"] == "express-checkout" ? "PayPal" : "Authorize.net" + end + +end diff --git a/app/models/viewer.rb b/app/models/viewer.rb new file mode 100644 index 0000000..9b8a5a5 --- /dev/null +++ b/app/models/viewer.rb @@ -0,0 +1,3 @@ +class Viewer < ActiveRecord::Base + acts_as_authentic +end diff --git a/app/models/viewer_session.rb b/app/models/viewer_session.rb new file mode 100644 index 0000000..2269803 --- /dev/null +++ b/app/models/viewer_session.rb @@ -0,0 +1,5 @@ +class ViewerSession < Authlogic::Session::Base +# specify configuration here, such as: +# logout_on_timeout true +# ...many more options in the documentation +end \ No newline at end of file diff --git a/app/sweepers/account_sweeper.rb b/app/sweepers/account_sweeper.rb new file mode 100644 index 0000000..6a96225 --- /dev/null +++ b/app/sweepers/account_sweeper.rb @@ -0,0 +1,7 @@ +class AccountSweeper < ActionController::Caching::Sweeper + observe Account + + def after_save(a) + Rails.cache.delete_matched("homepage/*/#{a.id}") if a.credits_changed? || a.bonuses_changed? + end +end \ No newline at end of file diff --git a/app/sweepers/product_sweeper.rb b/app/sweepers/product_sweeper.rb new file mode 100644 index 0000000..af001fa --- /dev/null +++ b/app/sweepers/product_sweeper.rb @@ -0,0 +1,11 @@ +class ProductSweeper < ActionController::Caching::Sweeper + observe Product + + def after_save(p) + #expire_action p + #expire_fragment(%r{member-shop/*}) # not working with Redis-Store, see https://github.com/jodosha/redis-store/pull/52 + if p.visible? || p.visible_changed? # invisible products need not be expired. However, on creation this will still expire. + Rails.cache.delete_matched "views/member-shop/*" + end + end +end \ No newline at end of file diff --git a/app/uploaders/main_picture_uploader.rb b/app/uploaders/main_picture_uploader.rb new file mode 100644 index 0000000..fd16a49 --- /dev/null +++ b/app/uploaders/main_picture_uploader.rb @@ -0,0 +1,34 @@ +# encoding: utf-8 + +class MainPictureUploader < CarrierWave::Uploader::Base + + include CarrierWave::ImageScience + include CarrierWave::Compatibility::Paperclip + + storage :file + + #def store_dir + # "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" + #end + + version :thumb do + process :resize_to_fit => [70, 65] + end + + version :small do + process :resize_to_fit => [120, 110] + end + + version :medium do + process :resize_to_fit => [280, 260] + end + + version :index do + process :resize_to_fit => [220, 204] + end + + def extension_white_list + %w(jpg jpeg gif png) + end + +end diff --git a/app/uploaders/product_image_uploader.rb b/app/uploaders/product_image_uploader.rb new file mode 100644 index 0000000..ec44ff7 --- /dev/null +++ b/app/uploaders/product_image_uploader.rb @@ -0,0 +1,26 @@ +# encoding: utf-8 + +class ProductImageUploader < CarrierWave::Uploader::Base + + include CarrierWave::ImageScience + include CarrierWave::Compatibility::Paperclip + + storage :file + + def paperclip_path + ":rails_root/public/system/datas/:id/:style/:basename.:extension" + end + + version :thumb do + process :resize_to_fit => [70, 65] + end + + version :medium do + process :resize_to_fit => [280, 260] + end + + def extension_white_list + %w(jpg jpeg gif png) + end + +end diff --git a/app/views/accounts/_form.html.haml b/app/views/accounts/_form.html.haml new file mode 100644 index 0000000..627f20c --- /dev/null +++ b/app/views/accounts/_form.html.haml @@ -0,0 +1,36 @@ += form_for @account, :url => account_path(:secure => true) do |f| + - if @account.errors.any? + #errorExplanation + %p Oops, please correct the following items to proceed: + %ul + - @account.errors.full_messages.each do |msg| + %li= msg + .field.input(style="margin-bottom:10px;") + = f.label :username, "Username:" + = f.text_field :username + #username-explanation + %p Usernames must be between 3 to 14 characters, and alphanumeric only (A-Z, 0-9). No spaces or special characters are allowed. + %p.last Please note: that your username will be viewable by others each time you bid. + .field.input + = f.label :email, "Email address:" + = f.text_field :email + .field.input + = f.label :password, "Password:" + = f.password_field :password + .field.input + = f.label :password_confirmation, "Confirm password:" + = f.password_field :password_confirmation + .field#dob + = f.label :birth_date, "Date of birth:", :class => "account-birth-date" + %span.account-birth-date + = f.date_select :birth_date, :start_year => Date.today.year, :end_year => 1910 + .checkbox-agreements + = f.check_box :subscribed + %p + = f.label :subscribed, "Send me coupons and exclusive offers via FirstBargain newsletters." + .checkbox-agreements#tos-agreement + = f.check_box :terms_of_service + %p + = f.label :terms_of_service, "I have read and agree to FirstBargain's #{ link_to "Terms of Service", tos_path(:popup=> true), :class=> "popup" } and #{link_to "Privacy Policy", privacy_path(:popup => true), :class=>"popup"}. I also agree to open one account per person and per household.".html_safe + .actions + = f.submit "Register For Free", :class => "button" diff --git a/app/views/accounts/create.html.haml b/app/views/accounts/create.html.haml new file mode 100644 index 0000000..edb68dd --- /dev/null +++ b/app/views/accounts/create.html.haml @@ -0,0 +1,12 @@ +- content_for :title, "FirstBargain.com - New Account Registration" + +#account-create-page.penny-promo.clearfix + #registration-wrapper.clearfix + %a(name="form-landing") + #testimonials + #registration-form + .header + .body + = render "form" + .footer + #penny-quotes \ No newline at end of file diff --git a/app/views/accounts/edit.html.haml b/app/views/accounts/edit.html.haml new file mode 100644 index 0000000..3d774f1 --- /dev/null +++ b/app/views/accounts/edit.html.haml @@ -0,0 +1,30 @@ +%h2.edit-account + Edit Account Information += form_for current_user, :url => account_path(:secure => true), :html => {:id => "update-account", :class => "dashboard-form"} do |f| + - if current_user.errors.any? + #errorExplanation + %p Oops, please correct the following items to proceed: + %ul + - current_user.errors.full_messages.each do |msg| + %li= msg + .field + = f.label :username, "Username" + = f.text_field :username + .field + = f.label :email + = f.text_field :email + .field + = f.label :password + = f.password_field :password + .field + = f.label :password_confirmation, "Confirm password" + = f.password_field :password_confirmation + .field(style="margin-bottom:15px;") + = f.label :birth_date + = f.date_select :birth_date, :start_year => 1910, :end_year => Time.now.year + .checkbox-agreements + = f.check_box :subscribed + %p + = f.label :subscribed, "Yes, please send me coupons and exclusive offers via FirstBargain newsletters." + .actions + = f.submit "Update Account", :class => "button" diff --git a/app/views/accounts/new.html.haml b/app/views/accounts/new.html.haml new file mode 100644 index 0000000..31ea741 --- /dev/null +++ b/app/views/accounts/new.html.haml @@ -0,0 +1,20 @@ +- content_for :title, "FirstBargain.com - New Account Registration" + +#registration-page.penny-promo.clearfix + #scroll-out + %a(href="#form-landing") + = image_tag "promo/registration-heading.jpg", size: "940x86" + #splash + #penny-head + #ended-auctions-text + #ended-auctions + #thousands-satisfied + #registration-wrapper.clearfix + %a(name="form-landing") + #testimonials + #registration-form + .header + .body + = render "form" + .footer + #penny-quotes \ No newline at end of file diff --git a/app/views/accounts/show.html.haml b/app/views/accounts/show.html.haml new file mode 100644 index 0000000..caf0598 --- /dev/null +++ b/app/views/accounts/show.html.haml @@ -0,0 +1,68 @@ +- unless current_user.verified? + .resend-verification-email + %p Please verify your email address to complete your account registration. + %p #{link_to "Resend the verification email", activation_path, :method => :post } or #{link_to "update your email", edit_account_path}. +.block-first + %h2.redeem-auctions + Auctions to Redeem + - if @winnings.empty? + %p You have no auctions to redeem. Keep playing! + - else + %p Congratulations! You've recently won something. Click "redeem" to process your order for shipping! + %p Please note: You have up to 7 days to redeem an auction after its closing. + %table#redeemable-auctions + %tr + %th.image + %th.name Product Name + %th.auction-price.alignC Auction Price + %th.shipping-price.alignC Shipping + %th.total-price.alignC Total + %th.redeem + - @winnings.each do |auction| + %tr + %td= link_to image_tag(auction.product.main_picture.url(:thumb), size: "70x65"), auction + %td= link_to auction.product.name, auction + %td.alignC= number_to_currency auction.going_price + %td.alignC= shipping_price auction.product + %td.alignC + %strong= number_to_currency auction.total_won_price + %td.alignC= link_to "Redeem", new_order_path(:buyable => auction.id, :kind => :auction), :class => "button" +.block-middle + %h2.my-wins My Wins + %p At First Bargain, you can win up to #{Rails.configuration.monthly_win_limit} times a month. This gives everyone a fair chance to win. + %table#auction-monthly-wins + - [Rails.configuration.monthly_win_limit, @wins.size].max.times do |i| + - if i.zero? + + - elsif i.multiple_of?(5) + + %td + %p + - if @wins[i] + = link_to image_tag(@wins[i].product.main_picture.url(:thumb), size: "70x65"), @wins[i] +.block-last + %h2.buynow-auctions Auctions to Buy Now + - if @buynows.empty? + %p You have no auctions to Buy Now. Check out our #{link_to "rewards page", rewards_path} to learn more about our Buy Now feature. + %p Please note: "Buy Now" is available for 24 hours after an auction has ended. + - else + %p You may "Buy Now" the following auctions. Check out our #{link_to "rewards page", rewards_path} to learn more about our Buy Now feature. + %p Please note: "Buy Now" is available for 24 hours after an auction has ended. + %table#buynow-auctions + %tr + %th.image + %th.name Product Name + %th.auction-price.alignC Buy Now Price + %th.shipping-price.alignC Shipping + %th.total-price.alignC Total + %th.redeem + - @buynows.each do |a| + %tr + %td= link_to image_tag(a.product.main_picture.url(:thumb), size: "70x65"), a + %td= link_to a.product.name, a + %td.alignC= number_to_currency a.buy_now_price(current_user) + %td.alignC= shipping_price a.product + %td.alignC + %strong= number_to_currency a.total_buy_now_price(current_user) + %td.alignC= link_to "Buy Now", new_order_path(:buyable => a.id, :kind => :buynow), :class => "button" + = will_paginate @buynows \ No newline at end of file diff --git a/app/views/accounts/welcome.html.haml b/app/views/accounts/welcome.html.haml new file mode 100644 index 0000000..3c657eb --- /dev/null +++ b/app/views/accounts/welcome.html.haml @@ -0,0 +1,32 @@ +- content_for :title, "FirstBargain.com - Purchase Bid Credits" + += render :file => 'bid_packs/first' + + +/ Google Code for Registration Conversion Tracking +:javascript + var google_conversion_id = 1021111885; + var google_conversion_language = "en"; + var google_conversion_format = "2"; + var google_conversion_color = "ffffff"; + var google_conversion_label = "U9r3CKvujAIQzdzz5gM"; + var google_conversion_value = 0; +%script{:src => "https://www.googleadservices.com/pagead/conversion.js"} +%noscript + %div{:style => "display:inline"} + %img(height="1" width="1" style="border-style:none;" alt="" src="https://www.googleadservices.com/pagead/conversion/1021111885/?label=U9r3CKvujAIQzdzz5gM&guid=ON&script=0") + +-# + / YAHOO! AD NETWORK + + + / ADBRITE SIGNUP TRACKER + + + / MYADS NETWORK TRACKER + :javascript + var rnd=10000000000*Math.random(); + document.write(""); + %noscript + + diff --git a/app/views/addresses/_address.html.haml b/app/views/addresses/_address.html.haml new file mode 100644 index 0000000..1e783b3 --- /dev/null +++ b/app/views/addresses/_address.html.haml @@ -0,0 +1,8 @@ +.address-listing + %address + %p #{address.label} + %p= address.name + %p= address.address + %p= address.address_2 if address.address_2 + %p #{address.city}, #{address.state} #{address.zip} + %p= link_to "remove", address, :method => :delete diff --git a/app/views/addresses/_form.html.haml b/app/views/addresses/_form.html.haml new file mode 100644 index 0000000..193580c --- /dev/null +++ b/app/views/addresses/_form.html.haml @@ -0,0 +1,36 @@ += form_for @address, :html => {:id => "new-address", :class => "dashboard-form address-form"} do |f| + - if @address.errors.any? + #errorExplanation + %p Oops, please correct the following items to proceed: + %ul + - @address.errors.full_messages.each do |msg| + %li= msg + .address_form + %p.field + = f.label :label + = f.text_field :label + %span.example (Home, School, Work, etc.) + %p.field + = f.label :name + = f.text_field :name + %p.field.address + = f.label :address + = f.text_field :address + %p.field.address + = f.label :address_2 + = f.text_field :address_2 + %p.field + = f.label :city + = f.text_field :city + .field.clearfix + %p.state + = f.label :state + = f.select :state, Address::STATES, :include_blank => true + %p.zip + = f.label :zip + = f.text_field :zip, :size => 5, :maxlength => 5 + %p.field + = f.label :phone + = f.text_field :phone + %p.actions + = f.submit "Save Address", :class => "button" diff --git a/app/views/addresses/index.html.haml b/app/views/addresses/index.html.haml new file mode 100644 index 0000000..3203342 --- /dev/null +++ b/app/views/addresses/index.html.haml @@ -0,0 +1,6 @@ +#addresses + %h2.saved-addresses Saved Addresses + %p.new-address + = link_to "Add New Address", new_address_path, :class=>"add-new-address button" + = render @addresses + \ No newline at end of file diff --git a/app/views/addresses/new.html.haml b/app/views/addresses/new.html.haml new file mode 100644 index 0000000..6e6a995 --- /dev/null +++ b/app/views/addresses/new.html.haml @@ -0,0 +1,5 @@ +%h2.new-address + New address +%p + = link_to "Back", addresses_path, :class => "back button" += render 'form' \ No newline at end of file diff --git a/app/views/admin/accounts/destroy.js.erb b/app/views/admin/accounts/destroy.js.erb new file mode 100644 index 0000000..cf42d4d --- /dev/null +++ b/app/views/admin/accounts/destroy.js.erb @@ -0,0 +1,5 @@ +<% if @account.active %> +$("#activation-link a").text("Yes").addClass("positive-admin-button").removeClass("negative-admin-button"); +<% else %> +$("#activation-link a").text("No").addClass("negative-admin-button").removeClass("positive-admin-button"); +<% end %> diff --git a/app/views/admin/accounts/flag.js.erb b/app/views/admin/accounts/flag.js.erb new file mode 100644 index 0000000..729b370 --- /dev/null +++ b/app/views/admin/accounts/flag.js.erb @@ -0,0 +1,5 @@ +<% if @account.good_email %> +$("#flag-link a").text("Yes").addClass("positive-admin-button").removeClass("negative-admin-button"); +<% else %> +$("#flag-link a").text("No").addClass("negative-admin-button").removeClass("positive-admin-button"); +<% end %> diff --git a/app/views/admin/accounts/index.html.haml b/app/views/admin/accounts/index.html.haml new file mode 100644 index 0000000..e153594 --- /dev/null +++ b/app/views/admin/accounts/index.html.haml @@ -0,0 +1,25 @@ +#accounts-admin.admin-page + .block-first + %h2 User Accounts + %p.admin-hints Search by Username, IP, or Email Address + = form_tag admin_accounts_path, :method => 'get' do + = text_field_tag :s, params[:s] + = submit_tag "Search", :name => nil, :class => "blue-button" + .block-last + %table + %tr + %th.username Username + %th.join-date Member Since + %th.bids Bids + %th.bonuses Bonuses + %th.points Points + %th.email Email + - @accounts.each do |a| + %tr + %td= link_to a.username, [:admin, a] + %td= a.created_at.to_s :default + %td= a.credits + %td= a.bonuses + %td= number_to_currency a.points + %td= mail_to a.email + = will_paginate @accounts diff --git a/app/views/admin/accounts/online.html.haml b/app/views/admin/accounts/online.html.haml new file mode 100644 index 0000000..ac25499 --- /dev/null +++ b/app/views/admin/accounts/online.html.haml @@ -0,0 +1,22 @@ +#accounts-admin.admin-page + .block-first + %h2 Online Accounts + %p.admin-hints Search by Username, IP, or Email Address + = form_tag admin_accounts_path, :method => 'get' do + = text_field_tag :s, params[:s] + = submit_tag "Search", :name => nil, :class => "blue-button" + .block-last + %table + %tr + %th.username Username + %th.last-request Last Request + %th.bids Bids + %th.bonuses Bonuses + %th.ip Current IP + - @accounts.each do |a| + %tr[a] + %td= link_to a.username, [:admin, a] + %td= a.last_request_at.to_s :default + %td= a.credits + %td= a.bonuses + %td= a.current_login_ip.blank? ? "N/A" : link_to(a.current_login_ip, admin_accounts_path(:s => a.current_login_ip)) \ No newline at end of file diff --git a/app/views/admin/accounts/show.html.haml b/app/views/admin/accounts/show.html.haml new file mode 100644 index 0000000..b0f74bb --- /dev/null +++ b/app/views/admin/accounts/show.html.haml @@ -0,0 +1,169 @@ +#accounts-admin.admin-page + - if @account.errors.any? + .block-first + #errorExplanation + %p Your changes were not saved: + %ul + - @account.errors.full_messages.each do |msg| + %li= msg + .block-middle.clearfix + %table.user-basics + %colgroup.label + %colgroup.value + %tr + %td Account ID + %td= @account.id + %tr + %td Email + %td= @account.email + %tr + %td Member Since + %td= @account.created_at.to_s :default + %tr + %td Date of Birth + %td= @account.birth_date + %tr + %td Verification + %td= @account.verified ? "verified".html_safe : "pending" + %tr + %td Active Account + %td#activation-link= link_to @account.active ? "Yes" : "No", [:admin, @account], :method => :delete, :remote => true, :class => (@account.active ? "positive-admin-button" : "negative-admin-button") + %tr + %td Valid Email + %td#flag-link= link_to @account.good_email ? "Yes" : "No", flag_admin_account_path(@account), :method => :put, :remote => true, :class => (@account.good_email ? "positive-admin-button" : "negative-admin-button") + %tr + %td Subscribed + %td#subscribed-link= link_to @account.subscribed? ? "Yes" : "No", subscribe_admin_account_path(@account), :method => :put, :remote => true, :class => (@account.subscribed? ? "positive-admin-button" : "negative-admin-button") + %tr + %td MemberPoints + %td= @account.points + %tr + %td Cumulative Bids + %td= @account.cumulative_credits + %tr + %td Cumulative Bonus Bids + %td= @account.cumulative_bonuses + %tr + %td Affiliate + %td= @account.source.blank? ? "---" : @account.source + %table.user-details + %colgroup.label + %colgroup.value + %tr + %td Username + %td + %strong= @account.username + %tr + %td Total Spent + %td= number_to_currency @account.total_spent + %tr + %td Bids + %td= @account.credits + %tr + %td Bonus Bids + %td= @account.bonuses + %tr + %td Customer P&L + %td= number_to_currency @account.profit_and_loss + %tr + %td Wins in the Last 7 Days + %td= @account.wins_this_week.size + %tr + %td Wins This Month + %td= @account.wins_this_month.size + %tr + %td Total Wins + %td= @account.auctions.inactive.size + %tr + %td Total Value of Purchases + %td= number_to_currency @account.total_cost + %tr + %td Registration IP + %td= @account.registration_ip.blank? ? "---" : link_to(@account.registration_ip, admin_accounts_path(:s => @account.registration_ip)) + %tr + %td Current IP + %td= @account.current_login_ip.blank? ? "---" : link_to(@account.current_login_ip, admin_accounts_path(:s => @account.current_login_ip)) + %tr + %td Last IP + %td= @account.last_login_ip.blank? ? "---" : link_to(@account.last_login_ip, admin_accounts_path(:s => @account.last_login_ip)) + %tr + %td Invited By + %td= @account.parent ? link_to(@account.parent.username, [:admin, @account.parent]) : "---" + .block-middle + %h2 All Won Auctions + %table + %tr + %th.id Auction ID + %th.date End Time + %th.status + %th.price Price + %th.contents Link to Auction + - @wins.each do |w| + %tr + %td= w.id + %td= w.ending_at.to_s :default + %td + %td= number_to_currency w.going_price + %td.contents= link_to w.product.name, w + .block-middle + %h2 Order History + #account-order-history + %table.order-history-hidden + %tr + %th.id Order ID + %th.date Order Date + %th.status Status + %th.price Price + %th.contents Content + - @orders.each do |o| + %tr{:class => o.state} + %td= o.id + %td= o.created_at.to_s :default + %td.status= o.state + %td= o.total_price + %td.items{:class => order_class(o)}= link_to o.contents, admin_order_path(o) + #show-void-declined.blue-button + Show Void & Declined Orders + -# + .block-middle + %h2 Bidding History + %table + %tr + %th.id ID + %th.date End Date + %th.bids Bids + %th.bids Bonuses + %th.contents Content + .block-middle + %h2 Admin Interface + %p.admin-hints You may enter negative values to deduct that amount. + %div(style="margin-bottom:55px;") + = form_for [:admin, @account], :url => adjust_admin_account_path do |f| + %p.field + = f.label :credits_increment + = f.text_field :credits_increment + %p.field + = f.label :bonuses_increment + = f.text_field :bonuses_increment + %p.field + = f.label :points_increment + = f.text_field :points_increment + %p.actions#update-item + = f.submit "Update Item", :class => "button" + %div + = form_for [:admin, @account] do |f| + %p.field + = f.label :notes + = f.text_area :notes + %p.actions#update-item + = f.submit "Note", :class => "button" + .block-last + %h2 Invitations + %table + %tr + %th Name + %th Status + - @invites.each do |c| + %tr + %td= link_to c.username, [:admin, c] + %td= c.verified ? "verified" : "pending" diff --git a/app/views/admin/accounts/subscribe.js.erb b/app/views/admin/accounts/subscribe.js.erb new file mode 100644 index 0000000..914b540 --- /dev/null +++ b/app/views/admin/accounts/subscribe.js.erb @@ -0,0 +1,5 @@ +<% if @account.subscribed? %> +$("#subscribed-link a").text("Yes").addClass("positive-admin-button").removeClass("negative-admin-button"); +<% else %> +$("#subscribed-link a").text("No").addClass("negative-admin-button").removeClass("positive-admin-button"); +<% end %> diff --git a/app/views/admin/analytics/index.html.haml b/app/views/admin/analytics/index.html.haml new file mode 100644 index 0000000..f221910 --- /dev/null +++ b/app/views/admin/analytics/index.html.haml @@ -0,0 +1,81 @@ +#analytics-admin.admin-page + = form_tag admin_analytics_path, :method => :get do + = select_tag :datatype, options_for_select([['Revenue from Users',:revenue],['Purchase Conversion Rate',:pcrate]], params[:datatype]) + = select_tag :source, options_for_select(['All Sources']+(@sources.to_a), params[:source]) + = select_tag :medium, options_for_select(['All Mediums']+@mediums.to_a, params[:medium]) + = select_tag :campaign, options_for_select(['All Campaigns']+@campaigns.to_a, params[:campaign]) + = select_tag :term, options_for_select(['All Terms']+@terms.to_a, params[:term]) + = select_tag :content, options_for_select(['All Content']+@contents.to_a, params[:content]) + = submit_tag "Filter", :name => nil, :class => "blue-button" + %br + %br + :javascript + $(function() { + $("#start").datepicker(); + $("#end").datepicker(); + }); + = label_tag 'From:' + = text_field_tag :start, nil, :placeholder => 'mm/dd/yyyy', :maxlength => 10, :value => (params[:start] ? params[:start] : nil) + = label_tag 'To:' + = text_field_tag :end, nil, :placeholder => 'mm/dd/yyyy', :maxlength => 10, :value => (params[:end] ? params[:end] : nil) + %h2(style="margin-top:55px;") + = "Analytics - #{(params[:datatype] == 'pcrate' ? "Purchase Conversion Rate" : "Revenue from Users")}" + - unless @graph_data[0].empty? + #analytics_graph + %script{:type => "text/javascript+protovis"} + - if params[:datatype] == 'pcrate' + - d = (@graph_data[3].keys.sort.inject("") {|a,v| a += "{x: new Date(\"#{v.strftime('%B %d, %Y')}\"), y: #{@graph_data[3][v]}},"})[0..-2] + - h_interval = 10 + - h = 100 + - else + - d = (@graph_data[0].keys.sort.inject("") {|a,v| a += "{x: new Date(\"#{v.strftime('%B %d, %Y')}\"), y: #{@graph_data[0][v]/100.0}},"})[0..-2] + - h_interval = (@graph_data[0].values.max > 0) ? (10 ** (Math.log10(@graph_data[0].values.max).floor - 2)) : 10 + - h = ((@graph_data[0].values.max / 100 / h_interval).to_i + 1) * h_interval + :plain + var data = [#{d}]; + var w = 600, + h = 300, + x = pv.Scale.linear(data, function(d) d.x).range(0,w), + y = pv.Scale.linear(0,#{h}).range(0,h); + + var vis = new pv.Panel() + .width(w) + .height(h) + .bottom(20) + .left(40) + .right(20) + .top(5) + + vis.add(pv.Rule) + .data(x.ticks()) + .left(x) + .strokeStyle("#eee") + .anchor("bottom").add(pv.Label) + .text(x.tickFormat); + + vis.add(pv.Rule) + .data(y.ticks(5)) + .bottom(y) + .strokeStyle(function(d) d ? "#eee" : "#000") + .anchor("left").add(pv.Label) + .text(y.tickFormat); + + vis.add(pv.Line) + .data(data) + .left(function(d) x(d.x)) + .bottom(function(d) y(d.y)) + .lineWidth(3); + + vis.render(); + %table(style="margin-top: 20px;") + %tr + %th.id Time Interval + %th.revenue Revenue + %th User Registrations + %th Unique Buyers + - @graph_data[0].keys.sort.each do |k| + %tr + %td= k.strftime("%m/%d/%Y") + %td= number_to_currency(@graph_data[0][k]/100.0) + %td= @graph_data[2][k] + %td= @graph_data[1][k] diff --git a/app/views/admin/auctions/_auction.html.haml b/app/views/admin/auctions/_auction.html.haml new file mode 100644 index 0000000..d6bcc86 --- /dev/null +++ b/app/views/admin/auctions/_auction.html.haml @@ -0,0 +1,5 @@ +%tr[auction] + %td= link_to auction.product.name, [:admin, auction] + %td= auction.ending_at.to_s :admin + %td= number_to_currency auction.going_price + %td= link_to 'Edit', edit_admin_auction_path(auction) \ No newline at end of file diff --git a/app/views/admin/auctions/_form.html.haml b/app/views/admin/auctions/_form.html.haml new file mode 100644 index 0000000..3dd484d --- /dev/null +++ b/app/views/admin/auctions/_form.html.haml @@ -0,0 +1,31 @@ +#auction-form.admin-form + = form_for [:admin, @auction] do |f| + - if @auction.errors.any? + #errorExplanation + %p The following errors occurred: + %ul + - @auction.errors.full_messages.each do |msg| + %li= msg + .field + = f.label :product + = f.collection_select :product_id, @products, :id, :name + .field + = f.label :ending_at + = f.datetime_select :ending_at + .field + = f.label :price_increment + = f.select :price_increment, [["$0.01", 0.01], ["$0.05", 0.05], ["$0.15", 0.15]] + .field + = f.label :timer_reset + = f.select :timer_reset, [["30 seconds", 30], ["20 seconds", 20]] + .field + = f.label :hot, "Feature when Ended" + = f.check_box :hot + .field + = f.label :is_buy_now + = f.check_box :is_buy_now + .field + = f.label :beginner + = f.check_box :beginner + .actions#add-item + = f.submit "Add Item", :class => "button" diff --git a/app/views/admin/auctions/destroy.js.erb b/app/views/admin/auctions/destroy.js.erb new file mode 100644 index 0000000..e1e1e81 --- /dev/null +++ b/app/views/admin/auctions/destroy.js.erb @@ -0,0 +1 @@ +$('#<%= dom_id @auction %>').hide("slide"); \ No newline at end of file diff --git a/app/views/admin/auctions/edit.html.haml b/app/views/admin/auctions/edit.html.haml new file mode 100644 index 0000000..de6dd07 --- /dev/null +++ b/app/views/admin/auctions/edit.html.haml @@ -0,0 +1,7 @@ +#auction-admin.admin-page.edit-page + %h2 Edit an Existing Auction + %p.nav-links.clearfix + = link_to 'Back', admin_auctions_path, :class => "button back" + = link_to 'Show', [:admin, @auction], :class => "button show" + = render 'form' + diff --git a/app/views/admin/auctions/index.html.haml b/app/views/admin/auctions/index.html.haml new file mode 100644 index 0000000..25e49b7 --- /dev/null +++ b/app/views/admin/auctions/index.html.haml @@ -0,0 +1,34 @@ +#auction-admin.admin-page + .block-first + %h2 Active Auctions + %p#add-new-item(style="margin-bottom:15px;")= link_to 'New auction', new_admin_auction_path, :class => "button" + %table + %tr + %th.name Product + %th.time Ending at + %th.price Price + %th.edit + = render @active + = will_paginate @active, :param_name => 'active' + .block-middle + %h2 Current Featured Auction + - if @featured + %table + %tr + %th.name Name + %th.time Ending at + %th.price Auction ID + %th.edit + = render @featured + - else + %p Nothing featured. + .block-last + %h2 Ended Auctions + %table + %tr + %th.name Product + %th.time Ending at + %th.price Price + %th.edit + = render @finished + = will_paginate @finished, :param_name => 'finished' \ No newline at end of file diff --git a/app/views/admin/auctions/new.html.haml b/app/views/admin/auctions/new.html.haml new file mode 100644 index 0000000..c10d699 --- /dev/null +++ b/app/views/admin/auctions/new.html.haml @@ -0,0 +1,7 @@ +#auction-admin.admin-page + %h2 Add a New Auction + %p.nav-links.clearfix + = link_to 'Back', admin_auctions_path, :class => "button back" + %p.admin-hints To list an auction in the "Upcoming" section, mark it as "hot" and give it an ending date of at least 24 hours in the future. + = render 'form' + diff --git a/app/views/admin/auctions/show.html.haml b/app/views/admin/auctions/show.html.haml new file mode 100644 index 0000000..8f3a067 --- /dev/null +++ b/app/views/admin/auctions/show.html.haml @@ -0,0 +1,21 @@ +#auction-admin.admin-page + %h2 #{ @auction.product.name } + %p.nav-links.clearfix + = link_to 'Back', admin_auctions_path, :class => "button back" + = link_to "View on Site", @auction, :class => "button", :id => "view-on-site" + = link_to "Feature this Auction", (new_admin_featured_auction_path + "?auction_id=#{@auction.id}"), :class => "button", :id => "feature-item" + = link_to 'Edit', edit_admin_auction_path(@auction), :class => "button edit" + .block-first + %p.auction-details Ending at: #{@auction.ending_at.to_s :admin} + %p.auction-details Going price: #{number_to_currency @auction.going_price} + %p.auction-details Last bidder: #{@auction.username} + .block-last + %h2 Bid history + %table + %tr + %th Bidder + %th Time + - @bids.each do |bid| + %tr + %td= link_to bid.username, [:admin, bid.account] + %td= bid.created_at.to_s :admin \ No newline at end of file diff --git a/app/views/admin/categories/edit.html.haml b/app/views/admin/categories/edit.html.haml new file mode 100644 index 0000000..ee42277 --- /dev/null +++ b/app/views/admin/categories/edit.html.haml @@ -0,0 +1,4 @@ += form_for [:admin, @category] do |f| + = f.label :name + = f.text_field :name + = f.submit "Update Category", :class => "blue-button" \ No newline at end of file diff --git a/app/views/admin/categories/index.html.haml b/app/views/admin/categories/index.html.haml new file mode 100644 index 0000000..0b9fdd1 --- /dev/null +++ b/app/views/admin/categories/index.html.haml @@ -0,0 +1,19 @@ +#category-admin.admin-page + .block-first + %h2 Category Listing + #add-new-item + = form_for @category, :url => admin_categories_path do |f| + .field.clearfix + = f.text_field :name + = f.submit "Add New Category", :class => "button" + .block-last + %table.categories + %tr + %th.name Categories + %th.id ID + %th.edit Edit + - @categories.each do |category| + %tr[category] + %td= category.id + %td.name= category.name + %td= link_to "Edit", edit_admin_category_path(category) \ No newline at end of file diff --git a/app/views/admin/coupons/index.html.haml b/app/views/admin/coupons/index.html.haml new file mode 100644 index 0000000..eecb07b --- /dev/null +++ b/app/views/admin/coupons/index.html.haml @@ -0,0 +1,17 @@ +#coupon-admin.admin-page + .block-first + %h2 Coupons + %p#add-new-item= link_to "New Coupon", new_admin_coupon_path, :class => "button" + .block-middle + %table + %tr + %th.uses-left Uses left + %th.ending-time Ends At + %th.summary Summary + %th.code Code + - @coupons.each do |c| + %tr + %td= c.uses_left + %td= c.ends_at.to_s :default + %td= c.summary + %td= c.code \ No newline at end of file diff --git a/app/views/admin/coupons/new.html.haml b/app/views/admin/coupons/new.html.haml new file mode 100644 index 0000000..9d29fa9 --- /dev/null +++ b/app/views/admin/coupons/new.html.haml @@ -0,0 +1,28 @@ +#coupon-admin.admin-page + .admin-form + %h2 New Coupon + = form_for @c, :url => admin_coupons_path do |f| + - if @c.errors.any? + #errorExplanation + %p The following errors occurred: + %ul + - @c.errors.full_messages.each do |msg| + %li= msg + %p.field + = f.label :code + = f.text_field :code + %p.field + = f.label :summary + = f.text_field :summary + %p.field + = f.label :ends_at + = f.datetime_select :ends_at + %p.field + = f.label :bonuses + = f.text_field :bonuses + %p.field + = f.label :uses_left, "Uses Left" + #{ f.text_field :uses_left } + %span (leave blank for no limit) + %p.actions#add-item + = f.submit "Add Item", :class => "button" diff --git a/app/views/admin/featured_auctions/_featured_auction.html.haml b/app/views/admin/featured_auctions/_featured_auction.html.haml new file mode 100644 index 0000000..e979571 --- /dev/null +++ b/app/views/admin/featured_auctions/_featured_auction.html.haml @@ -0,0 +1,5 @@ +%tr[featured_auction] + %td= link_to featured_auction.name, edit_admin_featured_auction_path(featured_auction) + %td= featured_auction.auction.ending_at.to_s :admin + %td= featured_auction.auction_id + %td= link_to 'Edit', edit_admin_featured_auction_path(featured_auction) \ No newline at end of file diff --git a/app/views/admin/featured_auctions/_form.html.haml b/app/views/admin/featured_auctions/_form.html.haml new file mode 100644 index 0000000..5cbd74b --- /dev/null +++ b/app/views/admin/featured_auctions/_form.html.haml @@ -0,0 +1,29 @@ +#auction-form.admin-form + = form_for [:admin, @featured] do |f| + - if @featured.errors.any? + #errorExplanation + %p The following errors occured: + %ul + - @featured.errors.full_messages.each do |msg| + %li= msg + + .field + = f.label "Auction ID" + - if params[:auction_id] then + = f.text_field :auction_id, :value => "#{params[:auction_id]}" + - else + = f.text_field :auction_id + .field + = f.label :name + = f.text_field :name + .field + = f.label :description + = f.text_area :description + .field + = f.label "Image URL" + - if params[:auction_id] then + = f.text_field :image_url, :value => "#{@auction.product.main_picture.url :medium}" + - else + = f.text_field :image_url + .actions#add-item + = f.submit "Add Item", :class => "button" \ No newline at end of file diff --git a/app/views/admin/featured_auctions/edit.html.haml b/app/views/admin/featured_auctions/edit.html.haml new file mode 100644 index 0000000..fa0acbf --- /dev/null +++ b/app/views/admin/featured_auctions/edit.html.haml @@ -0,0 +1,7 @@ +#auction-admin.admin-page.edit-page + %h2 Edit a Featured Auction + %p.nav-links.clearfix + = link_to 'Back', admin_featured_auctions_path, :class => "button back" + = render 'form' + + diff --git a/app/views/admin/featured_auctions/new.html.haml b/app/views/admin/featured_auctions/new.html.haml new file mode 100644 index 0000000..6fe9af3 --- /dev/null +++ b/app/views/admin/featured_auctions/new.html.haml @@ -0,0 +1,5 @@ +#auction-admin.admin-page + %h2 Create a New Featured Auction + %p.nav-links.clearfix + = link_to 'Back', admin_auctions_path, :class => "button back" + = render 'form' diff --git a/app/views/admin/featured_auctions/show.html.haml b/app/views/admin/featured_auctions/show.html.haml new file mode 100644 index 0000000..fe5b7be --- /dev/null +++ b/app/views/admin/featured_auctions/show.html.haml @@ -0,0 +1,13 @@ +#auction-admin.admin-page + %h2 FEATURED: #{ @featured.name } + %p.nav-links.clearfix + = link_to 'Back', admin_auctions_path, :class => "button back" + = link_to "View on Site", @featured.auction, :class => "button", :id => "view-on-site" + = link_to 'Edit', edit_admin_featured_auction_path(@featured), :class => "button edit" + .block-first + %p.auction-details + Auction: + = link_to "#{@featured.auction_id}", @featured.auction + %p.auction-details Name: #{@featured.name} + %p.auction-details Description: #{@featured.description} + %p.auction-details Image: #{@featured.image_url} diff --git a/app/views/admin/orders/index.html.haml b/app/views/admin/orders/index.html.haml new file mode 100644 index 0000000..ef675ef --- /dev/null +++ b/app/views/admin/orders/index.html.haml @@ -0,0 +1,23 @@ +#orders-admin.admin-page + = form_tag admin_orders_path, :method => :get do + = select_tag :type, options_for_select(Order::STATES, params[:type]) + = text_field_tag :s, params[:s] + = submit_tag "Filter", :name => nil, :class => "blue-button" + %h2(style="margin-top:55px;") #{params[:type].try :humanize} Orders + %table + %tr + %th.id ID + %th.username Username + %th.contents Contents + %th.price Price + %th.create-date Order Date + %th.ship-date Shipped Date + - @orders.each do |o| + %tr + %td= link_to o.id, admin_order_path(o) + %td= link_to o.account.username, admin_account_path(o.account) + %td.content=link_to o.contents, admin_order_path(o) + %td= number_to_currency o.total_price + %td= o.created_at.to_s :default + %td= o.shipped_at? ? o.shipped_at.to_s(:default) : "---" + = will_paginate @orders \ No newline at end of file diff --git a/app/views/admin/orders/show.html.haml b/app/views/admin/orders/show.html.haml new file mode 100644 index 0000000..feae180 --- /dev/null +++ b/app/views/admin/orders/show.html.haml @@ -0,0 +1,82 @@ +#orders-admin.admin-page + .orders-admin-show + %h2 #{@order.paypal? ? "PayPal" : "CCBill"} Order ##{@order.id} + %p.nav-links.clearfix + = link_to 'Back', admin_orders_path, :class => "button back" + .block-first.clearfix + .clearfix + %table.cart-price + %tr + %td.label Subtotal: + %td.value= number_to_currency @order.subtotal + %tr + %td.label Shipping: + %td.value= number_to_currency @order.shipping_price + %tr + %td.label Points: + %td.value= number_to_currency @order.point_discount + %tr + %td.label Grand Total: + %td.value.pink= number_to_currency @order.total_price + %table.user-cart + %tr + %td.label User: + %td.value= link_to @order.account.username, [:admin, @order.account] + %tr + %td.label #{order_contents_title @order}: + %td.value #{order_contents_link @order} + .main-product-image= order_picture @order + - if @order.requires_shipping? + .block-middle + %h2 Shipping Address + %address + #{@order.shipping_name} + %br + #{@order.shipping_address} + - if @order.shipping_address_2? + %br + #{@order.shipping_address_2} + %br + #{@order.shipping_city}, #{@order.shipping_state}, #{@order.shipping_zip} + %br + #{@order.shipping_phone} + - if @order.paid? + .block-middle + %h2 Confirmation Number + %p.admin-hints Leave blank to use a default message in the email. + = form_for @order, :as => :order, :url => ship_admin_order_path(@order), :method => :put do |f| + .field#ship-order + %p.clearfix + = f.label :confirmation + = f.text_field :confirmation + %p.clearfix + = f.label :tracking_id, "Tracking ID" + = f.text_field :tracking_id + %p.clearfix + = f.label :shipping_company + = f.text_field :shipping_company + %strong Case sensitive. Use FedEx, UPS, or USPS + = f.submit "Ship", :class => "button" + .block-middle + %h2 Other Actions + %p + = link_to "Refund Order", refund_admin_order_path(@order), :method => :put, :confirm => "Are you sure you want to refund this?", :class => "orange-button" + = link_to "Void Order", void_admin_order_path(@order), :method => :put, :confirm => "Are you sure you want to void this?", :class => "orange-button" + - if @order.under_review? + = link_to "Approve Order", approve_admin_order_path(@order), :method => :put, :class => "blue-button" + .block-last + %h2 Transactions + %table + %tr + %th.create-date Date + %th.id(style="width:17%;") ID + %th.amount Amount + %th.action Action + %th.message Message + - @order.transactions.each do |t| + %tr + %td= t.created_at.to_s :default + %td= t.authorization + %td= number_to_currency t.amount + %td= t.action + %td.message= t.message \ No newline at end of file diff --git a/app/views/admin/products/_form.html.haml b/app/views/admin/products/_form.html.haml new file mode 100644 index 0000000..97e3efa --- /dev/null +++ b/app/views/admin/products/_form.html.haml @@ -0,0 +1,68 @@ +#product-form + .right= image_tag(@product.main_picture.url, size: "280x260") if @product.main_picture? + = form_for([:admin, @product], :html => { :multipart => true }) do |f| + - if @product.errors.any? + #errorExplanation + %p The following errors occurred: + %ul + - @product.errors.full_messages.each do |msg| + %li= msg + .field + = f.label :widget_worthy + = f.check_box :widget_worthy + .field + = f.label :category + = f.collection_select :category_id, Category.order('name ASC'), :id, :name + .field + = f.label :name + = f.text_field :name + .field + = f.label :summary + = f.text_field :summary + .field + = f.label :retail_price + = f.text_field :retail_price, :class => "short" + .field + = f.label :max_discount + = f.text_field :max_discount, :class => "short" + .field + = f.label :shipping_price + = f.text_field :shipping_price, :class => "short" + .field + = f.label :tax + = f.text_field :tax, :class => "short" + .field + = f.label :cost + = f.text_field :cost, :class => "short" + .field + = f.label :visible, "In Store" + = f.check_box :visible + .field + = f.label :discontinued + = f.check_box :discontinued + .field + = f.label :bonuses, "Bonus Bids" + = f.text_field :bonuses, :class => "short" + .field + = f.label :requires_shipping, "Requires shipping?" + = f.check_box :requires_shipping + .field(style="margin-bottom:25px;") + = f.label :description + = f.text_area :description + %h2 Upload New Product Images: + .field + = f.label :main_picture + = f.file_field :main_picture + = f.hidden_field :main_picture_cache + %span « Recommended: 280px by 320px + = f.fields_for :pictures do |p| + .field.clearfix.secondary + %p.picture + = p.label :data, "other images" + = p.file_field :data + = p.hidden_field :data_cache + %p.summary + = p.label :summary + = p.text_field :summary, :class => "wide" + .actions#add-item + = f.submit "Add Item", :class => "button" diff --git a/app/views/admin/products/_product.html.haml b/app/views/admin/products/_product.html.haml new file mode 100644 index 0000000..be4a5e7 --- /dev/null +++ b/app/views/admin/products/_product.html.haml @@ -0,0 +1,9 @@ +%tr[product]{class: product.discontinued? ? "discontinued" : nil} + %td= product.id + %td.name= link_to product.name, [:admin, product] + %td= number_to_currency product.shipping_price + %td= number_to_currency product.cost + %td= product.bonuses + %td= (product.visible ? "Yes" : "No") + %td= number_to_currency product.retail_price + %td= link_to 'Edit', edit_admin_product_path(product) diff --git a/app/views/admin/products/destroy.js.erb b/app/views/admin/products/destroy.js.erb new file mode 100644 index 0000000..e89170f --- /dev/null +++ b/app/views/admin/products/destroy.js.erb @@ -0,0 +1 @@ +$('#<%= dom_id @product %>').remove(); \ No newline at end of file diff --git a/app/views/admin/products/edit.html.haml b/app/views/admin/products/edit.html.haml new file mode 100644 index 0000000..f81ec89 --- /dev/null +++ b/app/views/admin/products/edit.html.haml @@ -0,0 +1,6 @@ +#product-admin.admin-page.edit-page + %h2 Editing product + .nav-links.clearfix + = link_to 'Back', admin_products_path, :class => "button back" + = link_to 'Show', [:admin, @product], :class => "button show" + = render 'form' \ No newline at end of file diff --git a/app/views/admin/products/index.html.haml b/app/views/admin/products/index.html.haml new file mode 100644 index 0000000..4a9c31e --- /dev/null +++ b/app/views/admin/products/index.html.haml @@ -0,0 +1,33 @@ +#product-admin.admin-page + .block-first + %h2 Product Listing + %p#add-new-item(style="margin-bottom:15px;")= link_to 'Add New Product', new_admin_product_path, :class => "button" + %table + %thead + %tr + %th.id ID + %th.name Name + %th.shipping Shipping + %th.cost Cost + %th.bids Bids + %th.store Store + %th.price Price + %th.edit + %tbody + = render @active + .block-last + %h2 Discontinued Products + %p.admin-hints These products will not appear in the add new auction drop-down menu. You may re-enable a product by editing it's properties. + %table + %thead + %tr + %th.id ID + %th.name Name + %th.shipping Shipping + %th.cost Cost + %th.bids Bids + %th.store Store + %th.price Price + %th.edit + %tbody + = render @inactive diff --git a/app/views/admin/products/new.html.haml b/app/views/admin/products/new.html.haml new file mode 100644 index 0000000..061b5af --- /dev/null +++ b/app/views/admin/products/new.html.haml @@ -0,0 +1,6 @@ +#product-admin.admin-page + %h2 New product + .nav-links.clearfix + = link_to 'Back', admin_products_path, :class => "button back" + = render 'form' + diff --git a/app/views/admin/products/show.html.haml b/app/views/admin/products/show.html.haml new file mode 100644 index 0000000..f51aafa --- /dev/null +++ b/app/views/admin/products/show.html.haml @@ -0,0 +1,33 @@ +#product-admin.admin-page + %h2= @product.name + %p.nav-links.clearfix + = link_to 'Back', admin_products_path, :class => "button back" + = link_to 'Edit', edit_admin_product_path(@product), :class => "button edit" + .block-first + %p.admin-hints Summary field is used for SEO. Keep it short, catchy, and descriptive. + %table#product-show + %tr + %td.label Product Summary: + %td.value= @product.summary + %tr + %td.label Price: + %td.value= number_to_currency @product.retail_price + %tr + %td.label Shipping & Handling: + %td.value= number_to_currency @product.shipping_price + %tr + %td.label Sales Tax: + %td.value= number_to_currency @product.tax + %tr + %td.label Cost of Good: + %td.value= number_to_currency @product.cost + %tr + %td.label Description: + %td.value= simple_format @product.description + .block-middle + %h2 Main picture + = image_tag @product.main_picture.url(:thumb), size: "70x65" + .block-last + %h2 Additional pictures + - @product.pictures.each do |picture| + = image_tag picture.data.url(:thumb), size: "70x65" diff --git a/app/views/auctions/_auction-overlays.html.haml b/app/views/auctions/_auction-overlays.html.haml new file mode 100644 index 0000000..7749072 --- /dev/null +++ b/app/views/auctions/_auction-overlays.html.haml @@ -0,0 +1,42 @@ +#buy-now-popup.buy-now + %p.overlay-popup-toggle= image_tag "msc/close-icon.gif", size: "16x16" + %p.stop-message You should stop bidding! + %p.buy-now-price Buy this # for only # more! + %p.cheaper-than-hint **this is cheaper than the auction price plus one more bid. + %p.button= link_to "Buy Now", root_path, :class => "button" + %p.explanation How is the Buy Now price calculated? + %table + %tr.retail-price + %td.label Retail Value: + %td.value + %tr.credits-used + %td.label - Paid bids used (): + %td.value + %tr.bonuses-used + %td.label - Bonus bids used (): + %td.value $0.00 + %tr.buy-now-price + %td.label Buy Now Price: + %td.value +#error-overlay + %p.overlay-popup-toggle= image_tag "msc/close-icon.gif", size: "16x16" + %p.bid-unsuccessful Sorry, your bid did not succeed: + %p.explanation + +#error-modal-dialog + +- if (params[:beginner].present? or cookies[:beginner].present?) && (params[:page] == nil) + - cookies.delete :beginner + #beginner-auction-popup + .overlay-popup-toggle= image_tag "msc/close-icon.gif", size: "16x16" + .block + %p.welcome Try a beginner auction + .block + %p.question What are Beginner Auctions? + %p.answer They are auctions reserved only for new customers like you. You will see them marked with an orange border. + .block + %p.question Why start with a Beginner Auction? + %p.answer Because only newcomers can participate in them, these auctions are usually much easier to win. + .block.signature + %p Happy Bidding! + %p -- FirstBargain Team diff --git a/app/views/auctions/_auction.html.haml b/app/views/auctions/_auction.html.haml new file mode 100644 index 0000000..843f8da --- /dev/null +++ b/app/views/auctions/_auction.html.haml @@ -0,0 +1,38 @@ +%td.auction-listing{:class => auction_counter.next.multiple_of?(4) ? "last" : nil} + .product-container.clearfix[auction]{:class=> auction_classes(auction)} + .title + %h3= link_to auction.product.name, auction + %p Retail Value: #{number_to_currency auction.retail_price} + .image + = link_to image_tag(auction.product.main_picture.url(:index), size: "220x204"), auction + .bid-increment.hasTooltip{:title => increment_title(auction)} + .sold-overlay + = link_to auction.product.name, auction + .timer-container + .auction-timer loading... + .winner-text Winner! + .ended-text Ended! + %span.timer-reset-clock.hasTooltip{:title => timer_title(auction)} + .price-container + %span.auction-price= number_to_currency auction.going_price + .last-bidder-container + %span.auction-last-bidder= bidder auction.username(@winners) + .buttons + .main + .bid-button + - if logged_in? + = form_tag auction_bids_path(auction), :id => auction.id, :remote => true do + - if current_user.id == auction.account_id + = submit_tag "Bid", :class => "button", :disabled => true, :style => "background-position: 0 -120px" + - else + = submit_tag "Bid", :class => "button" + - elsif controller_name == "landings" + %a(href="#form-landing" class="registration button") + - else + = link_to "Login", new_session_path, :class => "login button" + .winner-button= link_to "Checkout", new_order_path(:buyable => auction.id, :kind => :auction), :class => "button" + .loser-button= link_to "Learn More", auction_path(auction, :auction_registration => true), :class => "button" + - if auction.beginner? + .auction-type-title-area.hasTooltip{:title => "Newcomers should try a beginner auction and learn how to bid against other newbies.
Same bargains, less competition!"} +- if auction_counter.next.multiple_of?(4) + \ No newline at end of file diff --git a/app/views/auctions/_buynow.html.haml b/app/views/auctions/_buynow.html.haml new file mode 100644 index 0000000..644a9aa --- /dev/null +++ b/app/views/auctions/_buynow.html.haml @@ -0,0 +1,32 @@ +#buy-now + %h3 Buy Now + - if @auction.can_buy_now? current_user + .available + %p.description Your discounted Buy Now price: + .clearfix + %table.highlight + %tr.retail-price + %td.label Retail value: + %td.value= number_to_currency @auction.retail_price + %tr.credits-used + %td.label - Paid bids used (#{ @investment.credits_used }): + %td.value #{ number_to_currency @investment.amount } + %tr.bonuses-used + %td.label - Bonus bids used (#{@investment.bonuses_used}): + %td.value $0.00 + %tr.buy-now-price + %td.label Buy Now price: + %td.value= number_to_currency @auction.buy_now_price(current_user) + %p.button= link_to "Buy Now", new_order_path(:buyable => @auction.id, :kind => :buynow), :class => "button" + - elsif @auction.won_by? current_user + .unavailable + %p Congratulations on winning this auction! + - elsif not @auction.is_buy_now + .unavailable + %p Due to inventory restrictions, Buy Now is not available for this product. + - elsif @auction.bought_by? current_user + .unavailable + %p Thank you for exercising the Buy Now option. + - else + .unavailable + %p Sorry, Buy Now is no longer available for this auction. \ No newline at end of file diff --git a/app/views/auctions/_endnumbers.html.haml b/app/views/auctions/_endnumbers.html.haml new file mode 100644 index 0000000..f095193 --- /dev/null +++ b/app/views/auctions/_endnumbers.html.haml @@ -0,0 +1,37 @@ +.auction-ended + %table.auction-numbers + %tr.winner + %td.alignC(colspan="2") + %p + Winner: #{ bidder @auction.username, true } + + %tr.price + %td.label Auction Price: + %td.value + %span.auction-price= number_to_currency @auction.going_price + %tr.credits-used + %td.label Paid bids placed by winner (#{ @investment.credits_used }): + %td.value= number_to_currency @winner_investment.amount + %tr.bonuses-used + %td.label Bonus bids placed by winner (#{@investment.bonuses_used}): + %td.value $0.00 + %tr.total-paid + %td.label Total paid by winner: + %td.value= number_to_currency @auction.total_winner_price + %tr.shipping + %td.label Shipping & Handling: + %td.value= shipping_price @auction.product + %tr.retail + %td.alignC(colspan="2") Retail Value: #{number_to_currency @auction.retail_price} + %tr.discount + %td.alignC(colspan="2") #{buy_now_percentage @winner_investment, @auction} Off + %tr.ended-text + %td.alignC(colspan="2") Auction Ended + %tr.time + %td.alignC(colspan="2") --- + .loser-button + %p.text Check out our other live auctions: + %p= link_to "Home", root_path, :class => "button" + .winner-button + %p.text.blue Congratulations! You've won! + %p= link_to "Checkout", new_order_path(:buyable => @auction.id, :kind => :auction), :class => "button" \ No newline at end of file diff --git a/app/views/auctions/_mainsplash.html.haml b/app/views/auctions/_mainsplash.html.haml new file mode 100644 index 0000000..ac59df6 --- /dev/null +++ b/app/views/auctions/_mainsplash.html.haml @@ -0,0 +1,85 @@ +#promo-slideshow + .wrapper.clearfix + #slideshow-content + - if logged_in? + .featured(style="display:block; background-image:url(#{@featured.image_url});") + %h2= @featured.name + %p= @featured.description + = link_to "Learn More", @featured.auction, :class => "button" + .tips + %h2 How to Win on FirstBargain.com + %p For tips & tricks: + = link_to "Learn More", tips_path, :class => "button" + .referral + %h2 Earn 20 Bids For Free! + %p Tell your friends about FirstBargain and receive 20 FREE Bonus Bids! If your friend signs up and makes a purchase, we’ll credit your account with 20 Bonus Bids. It’s that easy! + = link_to "Invite Friends", invitations_path, :class=>"button" + .facebook + %h2 Follow us on Facebook + %p Stay in the loop. You’ll find coupon codes, giveaways, and other great rewards. + = link_to "Our Facebook Page", "http://www.facebook.com/FirstBargain", :rel => "nofollow", :class => "button" + - else + .how-to(style="display:block;") + %h2 How Does FirstBargain Work? + %h3 Register & Buy Bids + %p Buy bids for $0.75 each to participate in auctions. + %h3 Choose an Auction + %p Pick from HDTV's, iPads, handbags & more. + %h3 Bid to Win! + %p Bid on an auction, last bidder when timer hits zero WINS! + %p.explanation Registration is FREE & easy + = link_to "Get Started", new_account_path, :class => "button" + .featured(style="background-image:url(#{@featured.image_url});") + %h2= @featured.name + %p= @featured.description + = link_to "Learn More", @featured.auction, :class => "button" + .bargains + + #slideshow-navigation + %ul + - if logged_in? + %li.featured + .first.current + %span Featured Auction + %li.tips + %div + %span Tips for Success + %li.referral + %div + %span Earn 20 Free Bids + %li.facebook + %div + %span Follow us on Facebook + - else + %li.how-to + .first.current + %span How It Works + %li.featured + %div + %span Featured Auction + %li.bargains + %div + %span Best Bargains + +:javascript + $("#slideshow-navigation li").click(function() { + var navClass = $(this).attr('class'); + var slideNav = $("#slideshow-navigation ul").children(); + var slideContents = $("#slideshow-content").children(); + + $(this).children(":first").addClass("current"); + $("#slideshow-content ." + navClass).show(); + + $.each(slideNav, function() { + var navClassOthers = $(this).attr("class"); + if (navClassOthers != navClass) { + $(this).children(":first").removeClass("current"); + } + }); + $.each(slideContents, function() { + var contentClass = $(this).attr("class"); + if (contentClass != navClass) { + $(this).hide(); + } + }); + }); \ No newline at end of file diff --git a/app/views/auctions/_runningnumbers.html.haml b/app/views/auctions/_runningnumbers.html.haml new file mode 100644 index 0000000..2e82405 --- /dev/null +++ b/app/views/auctions/_runningnumbers.html.haml @@ -0,0 +1,54 @@ +.auction-controls.clearfix + %table#main-numbers + %tr.price + %td.label Auction price: + %td.value + %p + %span.auction-price= number_to_currency @auction.going_price + %br + %span.shipping-price + +#{shipping_price @product} Shipping & Handling + %tr.bidder + %td.label Highest bidder: + %td.value + %p + %span.auction-last-bidder= bidder @auction.username, true + %tr.flash + %td(colspan="2") + %div.flash-text-wrapper + %p.auction-flash-text + %span.bid-increment.hasTooltip{:title => increment_title(@auction)} + %tr.timer + %td(colspan="2") + %p + %span.auction-timer loading... + %span.timer-reset-clock.hasTooltip{:title => timer_title(@auction)} + %tr.auction-buttons + %td(colspan="2") + .wrapper + .bid-button + - if logged_in? + = form_tag auction_bids_path(@auction), :remote => true, :id => @auction.id do + - if current_user.id == @auction.account_id + = submit_tag "Bid", :class => "button", :disabled => true, :style => "background-position: 0 -150px" + - else + = submit_tag "Bid", :class => "button" + - else + = link_to "login", new_session_path, :class => "button" + %table#current-numbers.highlight + %tr.retail-price + %td.label Retail value: + %td.value #{ number_to_currency @product.retail_price } + %tr.price + %td.label Auction price: + %td.value.auction-price= number_to_currency @auction.going_price + %tr.credits-used + %td.label Paid bids used (#{ @investment.credits_used }): + %td.value= number_to_currency @investment.amount + %tr.bonuses-used + %td.label Bonus bids used (#{@investment.bonuses_used}): + %td.value $0.00 + %tr.total-price + %td.label Total price: + %td.value= number_to_currency(@auction.going_price + @investment.amount) + #percent-off #{buy_now_percentage @investment, @auction} Off \ No newline at end of file diff --git a/app/views/auctions/index.html.haml b/app/views/auctions/index.html.haml new file mode 100644 index 0000000..39458d3 --- /dev/null +++ b/app/views/auctions/index.html.haml @@ -0,0 +1,20 @@ +- content_for :extra_headers do + :javascript + var SOURCE = "homepage"; + poller(#{auction_ids @auctions}, false, #{auction_prices @auctions}); + += render 'mainsplash' + +#auctions-index + .block-first + %h2.ending-soon + Ending soon! Bid now! + %table#main-auctions + %tr + = render @auctions + = fill_grid @auctions, "auction", 4 + = pagination @auctions += render 'auction-overlays' + +/ Yahoo! remarketing pixel +-# %img(src="http://ads.bluelithium.com/pixel?id=1052429&t=2" width="1" height="1") \ No newline at end of file diff --git a/app/views/auctions/show.html.haml b/app/views/auctions/show.html.haml new file mode 100644 index 0000000..c002b26 --- /dev/null +++ b/app/views/auctions/show.html.haml @@ -0,0 +1,87 @@ +- content_for :title, "#{@product.name} going for just #{number_to_currency @auction.going_price} at FirstBargain.com. Auction closes in #{time_ago_in_words @auction.ending_at}!" +- content_for :description, @product.summary +- content_for :extra_headers do + :javascript + RETAIL_PRICE = #{@auction.retail_price}; + PRICE_INCREMENT = #{@auction.price_increment}; + TIMER_RESET = #{@auction.timer_reset}; + var SOURCE = "details"; + poller([#{@auction.id}], true); + +#auction-details + .wrapper[@auction] + %table.product-name + %tr + %td + %h2= @product.name + %td#add-to-watchlist= link_to "Watch", bookmarks_path(:auction_id => @auction.id), :method => :post, :class => "button" + .clearfix{:class => auction_classes(@auction)} + #main-auction-grid + .block-first.clearfix + .product-images + #viewer= image_tag(@product.main_picture.url(:medium), size: "280x260") + %ul#gallery.clearfix + - @product.pictures.each do |p| + %li[p] + = image_tag(p.data.url(:thumb), size: "70x65") + :javascript + registerRollover("#{dom_id p}", #{p.data.url(:medium).to_json}); + = render 'runningnumbers' + = render 'endnumbers' + #product-description + %h2 Product Description + = simple_format @product.description + #secondary-auction-grid + //BID HISTORY/ASSISTANT OR REGISTRATION FORM + - if logged_in? + .block + #auction-bid-history + #bid-history-wrapper + %table#bid-history + %thead + %th.username User + %th.price Price + %th.time Time + %tbody + = render @auction.recent_bids + .block + #bid-assistant + %h3 + Bid Assistant + %a.about-bid-assistant.hasTooltip{:href => "#", :title => "Use the Bid Assistant to bid even while you're away from the computer. You can activate between 3 to 50 Bids at a time."} + .clearfix= render "bid_bots/form" + .learn-more To learn more about "Bid Assistant", #{ link_to "click here", faq_auctions_path(:anchor=>"5") }. + - else + #registration-form + = render "accounts/form" + .block= render 'buynow' + .wrapper + #social-media.clearfix + %p Share this: + %ul.left.clearfix-auto + %li= facebook_share_auction @auction + %li + .wrapper + #guarantee + .fb-guarantee= image_tag "text/fb-guarantee.gif" + %ul + %li Full refund on unused bid credits + %li Safe and fair auction environment + %li Risk-free rewards program + %li All items brand new & 100% authentic + %li 14-day return policy + %li.learn-more= link_to image_tag("text/product-description-learn-more.gif"), guarantee_path + + // SHIPPING INFORMATION + - unless @auction.product.bid_pack? + .shipping-information.clearfix + .title Shipping Information + .delivery-cost Delivery Cost: #{ shipping_price @product } + .return-policy + Return Policy: + - if [12,13,14,15,28,29].include? @auction.product.category_id + Gift cards are not eligible for returns + - else + Return within 14 days for any reason + .questions Any Questions? #{ link_to "Contact Us", contact_path } += render 'auction-overlays' diff --git a/app/views/auctions/static.html.haml b/app/views/auctions/static.html.haml new file mode 100644 index 0000000..e12d9e0 --- /dev/null +++ b/app/views/auctions/static.html.haml @@ -0,0 +1,114 @@ +- content_for :title, "#{@product.name} sold for #{number_to_currency @auction.going_price} at FirstBargain.com." +- content_for :description, @product.summary + +#auction-details + .wrapper.history-page[@auction] + %table.product-name + %tr + %td + %h2= @product.name + .clearfix{:class => auction_classes(@auction)} + #main-auction-grid + .block-first.clearfix + .product-images + #viewer= image_tag(@product.main_picture.url(:medium), size: "280x260") + %ul#gallery.clearfix + - @product.pictures.each do |p| + %li[p] + = image_tag(p.data.url(:thumb), size: "70x65") + :javascript + registerRollover("#{dom_id p}","#{p.data.url :medium}"); + .auction-ended + %table.auction-numbers + %tr.winner + %td.alignC(colspan="2") + %p + Winner: #{ bidder @auction.username, true } + + %tr.price + %td.label Auction Price: + %td.value + %span.auction-price= number_to_currency @auction.going_price + %tr.credits-used + %td.label Paid bids placed by winner (#{ @winner_investment.credits_used }): + %td.value= number_to_currency @winner_investment.amount + %tr.bonuses-used + %td.label Bonus bids placed by winner (#{@winner_investment.bonuses_used}): + %td.value $0.00 + %tr.total-paid + %td.label Total paid by winner: + %td.value= number_to_currency @auction.total_winner_price + %tr.shipping + %td.label Shipping & Handling: + %td.value +#{shipping_price @product} + %tr.retail + %td.alignC(colspan="2") Retail Value: #{ number_to_currency @auction.retail_price } + %tr.discount + %td.alignC(colspan="2") #{buy_now_percentage @winner_investment, @auction} Off + %tr.ended-text + %td.alignC(colspan="2") Auction Ended + %tr.time + %td.alignC(colspan="2") + #{ @auction.ending_at.to_s :auction } + - if @auction.won_by? current_user + .winner-button + %p.text.blue Congratulations! You've won! + - if @auction.redeemed + %p.redeemed Thanks for redeeming this item. + - elsif @auction.redemption_expired? + %p.redeemed Sorry, you can no longer redeem this item. + - else + %p= link_to "Checkout", new_order_path(:buyable => @auction.id, :kind => :auction), :class => "button" + - else + .loser-button + %p.text Check out our other live auctions: + %p= link_to "Home", root_path, :class => "button" + #product-description + %h2 Product Description + = simple_format @product.description + #secondary-auction-grid + //BID HISTORY/ASSISTANT OR REGISTRATION FORM + - if logged_in? + .block + #auction-bid-history + #bid-history-wrapper + %table#bid-history + %thead + %th.username User + %th.price Price + %th.time Time + %tbody + = render @auction.recent_bids + .block= render 'buynow' + - else + #registration-form + = render "accounts/form" + .wrapper + #social-media.clearfix + %p Share this: + %ul.left.clearfix-auto + %li= facebook_share_auction @auction + %li + .wrapper + #guarantee + .fb-guarantee= image_tag "text/fb-guarantee.gif" + %ul + %li Full refund on unused bid credits + %li Safe and fair auction environment + %li Risk-free rewards program + %li All items brand new & 100% authentic + %li 14-day return policy + %li.learn-more= link_to image_tag("text/product-description-learn-more.gif"), guarantee_path + + // SHIPPING INFORMATION + - unless @auction.product.bid_pack? + .shipping-information.clearfix + .title Shipping Information + .delivery-cost Delivery Cost: #{ shipping_price @product } + .return-policy + Return Policy: + - if [12,13,14,15,28,29].include? @auction.product.category_id + Gift cards are not eligible for returns + - else + Return within 14 days for any reason + .questions Any Questions? #{ link_to "Contact Us", contact_path } \ No newline at end of file diff --git a/app/views/auctions/winners.html.haml b/app/views/auctions/winners.html.haml new file mode 100644 index 0000000..d0db95e --- /dev/null +++ b/app/views/auctions/winners.html.haml @@ -0,0 +1,33 @@ +- content_for :title, "FirstBargain.com - Previous Auction Winners" + +#auctions-history + %h2.past-auction-winners + .auctions-ended + %table + %tr.title + %td.image + %td.product + %td.ended End Time + %td.price Total Price Paid + %td.savings Savings + - @auctions.each do |auction| + %tr.auction-listing[auction]{:class => auction_classes(auction) + [cycle('odd','even')]} + %td.image + = link_to image_tag(auction.product.main_picture.url :small), auction + %td.product + = link_to auction.product.name, auction + %td.ended + %span.ended-text Auction Ended
+ #{auction.ending_at.to_s :auction}
+ %span.winner Winner: #{bidder auction.username(@winners)} + %td.price + %span.auction-price #{ number_to_currency auction.total_winner_price }
+ Reg. Price: #{number_to_currency auction.retail_price} + %td.savings + #{buy_now_percentage auction.winner_investment, auction} off + = pagination(@auctions) + - unless logged_in? + #get-started + %h2.new-to-website New to First Bargain? + %p Welcome to FirstBargain.com, a fun and exciting auction website dedicated to bargain seekers.
At First Bargain you can win Playstations, iPads, gift cards, and all sorts of other popular products for incredibly low prices. + %p= link_to "Register For Free", new_account_path, :id => "signup-for-free", :class => "button" \ No newline at end of file diff --git a/app/views/bid_bots/_form.html.haml b/app/views/bid_bots/_form.html.haml new file mode 100644 index 0000000..cb19b79 --- /dev/null +++ b/app/views/bid_bots/_form.html.haml @@ -0,0 +1,9 @@ += form_for(@bot, :url => auction_bid_bot_path(@auction), :remote => true, :html => {:method => :post}) do |f| + .controls + .start-at + = f.label :bid_from, "Start at ($):" + = f.number_field :bid_from, :min => 0.0, :step => 0.01, :disabled => @bot.persisted? + .bid-limit + = f.label :bids_left, '# of Bids:' + = f.number_field :bids_left, :min => 3, :max => 50, :disabled => @bot.persisted? + = f.submit :class => "button" \ No newline at end of file diff --git a/app/views/bid_bots/create.js.erb b/app/views/bid_bots/create.js.erb new file mode 100644 index 0000000..7165eba --- /dev/null +++ b/app/views/bid_bots/create.js.erb @@ -0,0 +1,6 @@ +<% if @bot.errors.empty? %> +$("#bid-assistant form").replaceWith("<%= escape_javascript(render('form')) %>"); +A[<%= @auction.id %>].$bid_bot_bids_left = $("#bid_bot_bids_left"); +<% else %> +auctionDialog("Bid Assistant Unsuccessful", "<%= @bot.errors.full_messages.first %>"); +<% end %> diff --git a/app/views/bid_packs/first.html.haml b/app/views/bid_packs/first.html.haml new file mode 100644 index 0000000..8409515 --- /dev/null +++ b/app/views/bid_packs/first.html.haml @@ -0,0 +1,15 @@ +-# Add bid quantities to models/bid_order.rb + +.penny-promo + #welcome-page + %h2.almost-ready + #welcome-splash + #winners-table + #buy-bids-explanation + FirstBargain.com is the addictively fun shopping website where you can win name-brand items worth hundreds or even thousands of dollars for just pennies. To join the fun, you need Bid Credits #{ image_tag "icons/bids-single.png" }. Bid Credits allow you to bid on any FirstBargain auction, and they cost just 75¢ each. + = render :file => 'bid_packs/new' + #penny-quotes + +/ ADBRITE SIGNUP TRACKER + + \ No newline at end of file diff --git a/app/views/bid_packs/new.html.haml b/app/views/bid_packs/new.html.haml new file mode 100644 index 0000000..9a27973 --- /dev/null +++ b/app/views/bid_packs/new.html.haml @@ -0,0 +1,114 @@ +- content_for :title, "FirstBargain.com - Purchase Bid Credits" + +#new-bids-order.orders-page + %h2.buy-bids Buy Bids and Start Winning + .clearfix + = form_for @order, :as => :order, :url => confirm_orders_path(:secure => true), :html => {:id => "buy-bid-form", :class => "address-form"} do |f| + - if @order.errors.any? + #errorExplanation + %p Oops, please correct the following items to proceed: + %ul + - @order.errors.full_messages.each do |msg| + %li= msg + .left-column-4 + .wrapper + %h3.bid-packages Bid packages + -# If you change these quantities or prices, change those in app/models/bid_order.rb as well! + %p.bid-pack.clearfix + = f.radio_button :quantity, "200" + %label(for="order_quantity_200") 200 Bids$150.00 + %p.bid-pack.clearfix + = f.radio_button :quantity, "100" + %label(for="order_quantity_100") 100 Bids$75.00 + %p.bid-pack.recommended-bid-pack.clearfix + = f.radio_button :quantity, "50", :checked => "checked" + %label(for="order_quantity_50") 50 Bids$37.50 + %p.bid-pack.clearfix(style="margin-bottom:25px;") + = f.radio_button :quantity, "30" + %label(for="order_quantity_30") 30 Bids$22.50 + #satisfaction-guarantee + %ul + %li Get a full refund for any unused Bid Credits + %li Safe and fair bidding environment + %li All items brand new and 100% authentic + %p#us-shipping-only ** We ship only within the contiguous 48 U.S. states + + .right-column-4 + = f.hidden_field :gateway, :value => "authorize" + %h2.payment Payment Options + #payment-tabs + %ul.clearfix + %li#cc-tab.selected Credit Card + %li#pp-tab PayPal + #credit-card-form.clearfix + -# + #checkout-payments + %p.field + = f.label :first_name + = f.text_field :first_name + %p.field + = f.label :last_name + = f.text_field :last_name + %p.field.cc-type + = f.label :card_type + = f.select :card_type, [["Visa", "visa"], ["MasterCard", "master"]] + = image_tag "cc/visa-mc.gif", :alt => "visa-mastercard" + %p.field + = f.label :card_number + = f.text_field :card_number, :autocomplete => "off" + %p.field.cvv + = f.label :card_verification, "CVV" + = f.text_field :card_verification, :class => "small", :autocomplete => "off" + %p.field + = f.label :card_expires_on, "Expiration" + = f.date_select :card_expires_on, :discard_day => true, :start_year => Date.today.year, :end_year => Date.today.year + 10 + .separator + #checkout-address + -# + %p.field.address + = f.label :billing_address + = f.text_field :billing_address + %p.field.address + = f.label :billing_address_2, "Address 2" + = f.text_field :billing_address_2 + %p.field + = f.label :billing_city, "City" + = f.text_field :billing_city + .field.clearfix + %p.state + = f.label :billing_state, "State" + = f.select :billing_state, Address::STATES + %p.zip + = f.label :billing_zip, "Zip" + = f.text_field :billing_zip, :size => 5, :maxlength => 5 + %p.field.phone + = f.label :billing_phone + = f.text_field :billing_phone + %p.phone-example e.g. 305-555-0123 + %p Check out using Visa, MasterCard, or Discover. + %p.action + = f.submit "Confirm Order", :class => "button" + #paypal-form + = image_tag "text/paypal.png" + %h3 + PayPal is the safer, easier way to pay + %ul + %li Never expose your credit card number. + %li Speed through checkout all over the web. One account, one password - no need to retype your shipping or financial information. + %p.action + = f.submit "Pay with PayPal", :class => "button" + +/ Google Remarketing Tracker for New Customers +:javascript + var google_conversion_id = 1021111885; + var google_conversion_language = "en"; + var google_conversion_format = "3"; + var google_conversion_color = "666666"; + var google_conversion_label = "g2aMCLOZrQIQzdzz5gM"; + var google_conversion_value = 0; + +%script(src="//www.googleadservices.com/pagead/conversion.js") + +%noscript + %div(style="display:inline;") + %img(height="1" width="1" src="//www.googleadservices.com/pagead/conversion/1021111885/?label=g2aMCLOZrQIQzdzz5gM&guid=ON&script=0") \ No newline at end of file diff --git a/app/views/bids/_bid.html.haml b/app/views/bids/_bid.html.haml new file mode 100644 index 0000000..76e0f83 --- /dev/null +++ b/app/views/bids/_bid.html.haml @@ -0,0 +1,4 @@ +%tr + %td= bidder bid.username + %td= number_to_currency bid.price(bid_counter) + %td.time= bid.created_at.to_s :bid \ No newline at end of file diff --git a/app/views/bids/buynow.js.haml b/app/views/bids/buynow.js.haml new file mode 100644 index 0000000..af36a3c --- /dev/null +++ b/app/views/bids/buynow.js.haml @@ -0,0 +1,9 @@ +$('#buy-now-popup .credits-used .value').text("#{number_to_currency @bid.investment.amount}"); +$('#buy-now-popup .buy-now-price .value').text("#{number_to_currency @auction.buy_now_price(current_user)}"); +$('#buy-now-popup .credits-used-count').text("#{@bid.investment.credits_used}"); +$('#buy-now-popup .bonuses-used-count').text("#{@bid.investment.bonuses_used}"); +$('#buy-now-popup .popup-product-name').text("#{@auction.product.name}"); +$('#buy-now-popup .retail-price .value').text("#{number_to_currency @auction.retail_price}"); +$('#buy-now-popup .button').attr('href', "#{new_order_path :buyable => @auction.id, :kind => :buynow}"); +$("#buy-now-popup").show(); +A[#{@bid.auction_id}].bidding = false; \ No newline at end of file diff --git a/app/views/bids/failure.js.haml b/app/views/bids/failure.js.haml new file mode 100644 index 0000000..8db6229 --- /dev/null +++ b/app/views/bids/failure.js.haml @@ -0,0 +1,4 @@ +$(".credits").text(#{current_user.credits}); +$(".bonuses").text(#{current_user.bonuses}); +auctionDialog("Bidding Unsuccessful", "#{@bid.errors.full_messages.first}"); +A[#{@bid.auction_id}].bidding = false; \ No newline at end of file diff --git a/app/views/bids/silence.js.haml b/app/views/bids/silence.js.haml new file mode 100644 index 0000000..765b6b2 --- /dev/null +++ b/app/views/bids/silence.js.haml @@ -0,0 +1 @@ +A[#{@auction.id}].bidding = false; \ No newline at end of file diff --git a/app/views/bids/success.js.haml b/app/views/bids/success.js.haml new file mode 100644 index 0000000..8d9748e --- /dev/null +++ b/app/views/bids/success.js.haml @@ -0,0 +1,4 @@ +$(".credits-count").text(#{current_user.credits}); +$(".bonuses-count").text(#{current_user.bonuses}); +$("#bid-status").flash("

Success:

Bid at #{@bid.created_at.to_s :bid}

", 1500); +A[#{@bid.auction_id}].bidding = false; \ No newline at end of file diff --git a/app/views/bookmarks/destroy.js.haml b/app/views/bookmarks/destroy.js.haml new file mode 100644 index 0000000..73e26c1 --- /dev/null +++ b/app/views/bookmarks/destroy.js.haml @@ -0,0 +1 @@ +$('##{dom_id @auction}').hide(); \ No newline at end of file diff --git a/app/views/bookmarks/index.html.haml b/app/views/bookmarks/index.html.haml new file mode 100644 index 0000000..42ee36a --- /dev/null +++ b/app/views/bookmarks/index.html.haml @@ -0,0 +1,54 @@ +- content_for :extra_headers do + :javascript + var SOURCE = "watchlist"; + poller(#{auction_ids @watchlist}, false, #{auction_prices @watchlist}); + +%h2.watchlist + Watchlist +- if @watchlist.empty? + %p You aren't watching any items. +- else + %table#watchlist-auctions + %tr + %th.image + %th.title + Product Name + %th.timer + Time Left + %th.price + Price + %th.bidder + Last Bidder + %th.bid-button + %th.delete + - @watchlist.each do |auction| + %tr.auction-listing[auction] + %td.image + = link_to image_tag(auction.product.main_picture.url(:thumb), size: "70x65"), auction + %td.title + = link_to auction.product.name, auction + %td.timer + %span.timer-container + %span.auction-timer + Loading... + %span.winner-text Winner! + %span.ended-text Ended! + %td.price + %span.auction-price + = number_to_currency auction.going_price + %td.bidder + %span.auction-last-bidder + = auction.username + %td.winner-button + = link_to "Checkout", new_order_path(:buyable => auction.id, :kind => :auction), :class => "button" + %td.loser-button + = link_to "Learn More", auction, :class => "button" + %td.bid-button + = form_tag auction_bids_path(auction), :id => auction.id, :remote => true do |f| + - if current_user == auction.account + = submit_tag "Bid", :class => "button", :disabled => true, :style => "background-position: 0 -120px" + - else + = submit_tag "Bid", :class => "button" + %td.delete + = link_to "delete", bookmark_path(auction.id), :method => :delete, :remote => true += render 'auctions/auction-overlays' \ No newline at end of file diff --git a/app/views/contacts/show.html.haml b/app/views/contacts/show.html.haml new file mode 100644 index 0000000..95229bc --- /dev/null +++ b/app/views/contacts/show.html.haml @@ -0,0 +1,25 @@ +%h2.contact-us Contact Us +#how-to-contact + %p.blurb We always love to hear from our customers. For product inquiries, shipping status, and refund requests, please fill out the form below and we will get back to you in 24 - 48 hours. + %p.blurb For questions regarding credit card billing statements, please contact our billing partner: + %p.ccbill-contact Website: http://support.ccbill.com
Phone: 1-877-374-0182
Email: ccbillsupport@ccbill.com += form_for @contact, :url => contact_path, :html => {:id => "contact-form"} do |f| + - if @contact.errors.any? + #errorExplanation + %p Oops, please correct the following items to proceed: + %ul + - @contact.errors.full_messages.each do |msg| + %li= msg + %p.field + = f.label :email + = f.text_field :email, :value => current_user.try(:email) + %p.field + = f.label :subject + = f.text_field :subject + %p.field + = f.label :message + = f.text_area :message + %p.field + = captcha + %p.actions + = f.submit "Submit", :class => "button" diff --git a/app/views/coupons/new.html.haml b/app/views/coupons/new.html.haml new file mode 100644 index 0000000..c725fbc --- /dev/null +++ b/app/views/coupons/new.html.haml @@ -0,0 +1,14 @@ +#redeem-coupons-page + %h2.redeem-coupon-codes Redeem Coupon Codes + %p FirstBargain frequently offer our members special rewards that can be redeemed through the form below.
Follow us on Facebook to be in the know. + = form_for @c, :id => "new-coupon", :url => coupons_path do |f| + - if @c.errors.any? + #errorExplanation + %p Oops, please correct the following items to proceed: + %ul + - @c.errors.full_messages.each do |msg| + %li= msg + %p.field + = f.label :code, "Enter Coupon Code:" + = f.text_field :code + = f.submit "Redeem Coupon", :class => "button" diff --git a/app/views/customer_mailer/activation_instructions.html.haml b/app/views/customer_mailer/activation_instructions.html.haml new file mode 100644 index 0000000..fc87bba --- /dev/null +++ b/app/views/customer_mailer/activation_instructions.html.haml @@ -0,0 +1,19 @@ +- content_for :subject, "Account Activation" + +%tr + %td{:width=>"630px", :style=>"padding-top:0px; padding-bottom:20px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px; line-height:20px;"} Welcome to FirstBargain! We are glad to see that you have joined us, and we look forward to bringing you amazing deals through our exciting fast-paced auctions. You are just one step away from completing your registration and confirming your e-mail address with us. You have 24 hours to finish this process, so we encourage you to go ahead and do it now. +%tr + %td{:width=>"630px", :style=>"padding-top:0px; padding-bottom:20px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px; line-height:20px;"} Please confirm your email address by following the link below: +%tr + %td{:width=>"630px", :style=>"padding-top:0px; padding-bottom:20px; text-align:left;"} + %a{:href => new_activation_url(:code => @account.single_access_token), :style => "color:#EF7A25;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#EF7A25; font-size:13px; line-height:20px;"} + = new_activation_url :code => @account.single_access_token +%tr + %td{:width=>"630px", :style=>"padding-top:0px; padding-bottom:20px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px; line-height:20px;"} If you have trouble viewing this link, please copy and paste the entire link into your web browser. +%tr + %td{:width=>"630px", :style=>"padding-top:0px; padding-bottom:20px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px; line-height:20px;"} We require email address confirmation to prevent abuse of our system, and to make sure you receive important notifications from us. \ No newline at end of file diff --git a/app/views/customer_mailer/forgot_password.html.haml b/app/views/customer_mailer/forgot_password.html.haml new file mode 100644 index 0000000..2cb31bb --- /dev/null +++ b/app/views/customer_mailer/forgot_password.html.haml @@ -0,0 +1,10 @@ +- content_for :subject, "Password Reset Help" + +%tr + %td{:width=>"630px", :style=>"padding-top:0px; padding-bottom:20px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px; line-height:20px;"} A request to reset your password has been made. If you did not make this request, simply ignore this email. If you did make this request, please click on the link below to continue: +%tr + %td{:width=>"630px", :style=>"padding-top:0px; padding-bottom:20px; text-align:left;"} + %a{:href => edit_password_reset_url(:code => @account.perishable_token), :style => "color:#EF7A25;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#EF7A25; font-size:13px; line-height:20px;"} + = edit_password_reset_url :code => @account.perishable_token diff --git a/app/views/customer_mailer/invitation.html.haml b/app/views/customer_mailer/invitation.html.haml new file mode 100644 index 0000000..d13b164 --- /dev/null +++ b/app/views/customer_mailer/invitation.html.haml @@ -0,0 +1,39 @@ +%table{:width =>"100%", :border=>"0", :cellpadding=>"0", :cellspacing=>"0"} + %tbody + %tr + %td{:align=>"center", :bgcolor=>"#ffa524", :style=>"padding-top:30px; padding-bottom:20px;"} + / TOP WRAPPER + %table{:border=>"0", :cellpadding=>"0", :cellspacing=>"0", :width=>"670px", :height=>"5px"} + %tr + %td{:width=>"670px", :height=>"5px"}=image_tag 'http://www.firstbargain.com/images/email/v030311/top-wrap.png', :width=>"670px", :height=>"5px", :style=>"display:block;", :alt=>"FirstBargain.com Top Wrapper" + / WRAPPER CONTAINER + %table{:width => "670px", :border=>"0", :cellpadding=>"0", :cellspacing => "0"} + %tr + %td{:width=>"20px", :bgcolor=>"#FFFFFF"} + %td{:width=>"630px", :bgcolor=>"#FFFFFF", :align=>"center"} + / HEADER + %table{:width=>"630px", :height=>"60px", :border=>"0", :cellpadding=>"0", :cellspacing=>"0"} + %tr + %td{:width=>"195px", :height=>"60px"}=image_tag 'http://www.firstbargain.com/images/email/v030311/logo.gif', :width=>"195px", :height=>"60px", :style=>"display:block;", :alt=>"FirstBargain.com Logo" + %td{:width=>"475px", :height=>"60px"} + / BODY + %table{:width=>"630px", :border=>"0", :cellpadding=>"0", :cellspacing=>"0"} + %tr + %td{:width=>"630px", :style=>"padding-top:20px; padding-bottom:40px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px; line-height:20px;"} + = simple_format @message + / NAVIGATION + %table{:width=>"630px", :height=>"35px", :border=>"0", :cellpadding=>"0", :cellspacing=>"0", :background=>"http://www.firstbargain.com/images/email/v030311/nav-bar.png"} + %tr + %td{:width=>"630px", :height=>"35px", :align=>"center", :style=>"text-align:center;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#FFFFFF; font-size:15px;"} + #{link_to "Home", auctions_url, :style=>"font-family:Helvetica,Arial,sans-serif; color:#FFFFFF; font-size:15px; text-decoration:none; padding-left:12px; padding-right:12px;"} | + #{link_to "Members Shop", products_url, :style=>"font-family:Helvetica,Arial,sans-serif; color:#FFFFFF; font-size:15px; text-decoration:none; padding-left:12px; padding-right:12px;"} | + #{link_to "My Account", account_url, :style=>"font-family:Helvetica,Arial,sans-serif; color:#FFFFFF; font-size:15px; text-decoration:none; padding-left:12px; padding-right:12px;"} | + #{link_to "How It Works", tutorial_url, :style=>"font-family:Helvetica,Arial,sans-serif; color:#FFFFFF; font-size:15px; text-decoration:none; padding-left:12px; padding-right:12px;"} | + #{link_to "Help", faq_url, :style=>"font-family:Helvetica,Arial,sans-serif; color:#FFFFFF; font-size:15px; text-decoration:none; padding-left:12px; padding-right:12px;"} + %td{:width=>"20px", :bgcolor=>"#FFFFFF"} + / BOTTOM WRAPPER + %table{:border=>"0", :cellpadding=>"0", :cellspacing=>"0", :width=>"670px", :height=>"20px"} + %tr + %td{:width=>"670px", :height=>"20px"}=image_tag 'http://www.firstbargain.com/images/email/v030311/bot-wrap.png', :width=>"670px", :height=>"20px", :style=>"display:block;", :alt=>"FirstBargain.com Bottom Wrapper" diff --git a/app/views/customer_mailer/order_confirmation.html.haml b/app/views/customer_mailer/order_confirmation.html.haml new file mode 100644 index 0000000..d036ff2 --- /dev/null +++ b/app/views/customer_mailer/order_confirmation.html.haml @@ -0,0 +1,50 @@ +- content_for :subject, "Order Help" + +%tr + %td{:width=>"630px", :style=>"padding-top:0px; padding-bottom:20px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px; line-height:20px;"} + - if @order.is_a? BidOrder + Thank you for purchasing a bid pack. The appropriate amount of Bid Credits and MemberPoints have + been credited to your account, and they are available for your immediate use. + - elsif @order.bid_pack? and @order.requires_shipping? + Thank you for your payment. Your bids are ready for immediate use, and you will receive a shipping confirmation email shortly + - elsif @order.bid_pack? + Thank you for your payment. The appropriate number of Bonus Bids have been credited to your + account, and they are available for your immediate use. + - else + Thank you for your payment. Your order has been placed with our supplier, and you will receive a + shipping confirmation email shortly. +%tr + %td{:width=>"630px", :style=>"padding-top:0px; padding-bottom:20px; text-align:left;"} + %table{:border => "0", :cellpadding => "0", :cellspacing => "0"} + %tr{:valign => "top"} + %td{:width=>"80px", :style => "padding-left:100px; padding-right:0; padding-top:0; padding-bottom:5px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px;"} Product: + %td{:width=>"440px", :style => "padding-left:10px; padding-right:0; padding-top:0; padding-bottom:5px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px;"}= @order.contents + %tr{:valign=>"top"} + %td{:width=>"80px", :style => "padding-left:100px; padding-right:0; padding-top:0; padding-bottom:5px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px;"} Price: + %td{:width=>"440px", :style => "padding-left:10px; padding-right:0; padding-top:0; padding-bottom:5px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px;"}= number_to_currency @order.total_price +%tr + %td{:width=>"630px", :style=>"padding-top:0px; padding-bottom:20px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px; line-height:20px;"} This order was billed to the following address: +%tr + %td{:width=>"630px", :style=>"padding-top:0px; padding-bottom:20px; text-align:left;"} + %table{:border => "0", :cellpadding => "0", :cellspacing => "0"} + %tr + %td{:width=>"400px", :style=>"padding-left:100px; padding-right:0; padding-top:0; padding-bottom:5px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px;"}= @order.billing_name + %tr + %td{:width=>"400px", :style=>"padding-left:100px; padding-right:0; padding-top:0; padding-bottom:5px; text-align:left;"} + - if @order.paypal? + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px; font-style:italic;"} paid via PayPal + - else + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px;"} + = @order.billing_address + %br + - if @order.billing_address_2? + = @order.billing_address_2 + %br + #{@order.billing_city}, #{@order.billing_state} #{@order.billing_zip} \ No newline at end of file diff --git a/app/views/customer_mailer/shipment_confirmation.html.haml b/app/views/customer_mailer/shipment_confirmation.html.haml new file mode 100644 index 0000000..b667832 --- /dev/null +++ b/app/views/customer_mailer/shipment_confirmation.html.haml @@ -0,0 +1,12 @@ +- content_for :subject, "Shipment Confirmation" + +%tr + %td{:width=>"630px", :style=>"padding-top:0px; padding-bottom:20px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px; line-height:20px;"} Your #{@order.contents} has been shipped. +%tr + %td{:width=>"630px", :style=>"padding-top:0px; padding-bottom:20px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px; line-height:20px;"} + - if @order.confirmation? + Your confirmation number is #{@order.confirmation} + - else + Please allow 5 to 10 business days for delivery. \ No newline at end of file diff --git a/app/views/customer_mailer/welcome.html.haml b/app/views/customer_mailer/welcome.html.haml new file mode 100644 index 0000000..09b957e --- /dev/null +++ b/app/views/customer_mailer/welcome.html.haml @@ -0,0 +1,40 @@ +- content_for :subject, "Welcome to FirstBargain" + +%tr + %td{:width=>"630px", :style=>"padding-top:0px; padding-bottom:20px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px; line-height:20px;"} Thank you for registering with FirstBargain, an exciting, fast-paced auction site with great bargains and member rewards. +%tr + %td{:width=>"630px", :style=>"padding-top:0px; padding-bottom:20px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px; line-height:20px;"} Before you start bidding, we wanted to answer any questions you may have about our site. We believe it is important for you to first understand how our auctions work so you may have the most enjoyable experience on FirstBargain. +%tr + %td{:width=>"630px", :style=>"padding-top:0px; padding-bottom:20px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px; line-height:20px; font-weight:bold;"} How FirstBargain works: +%tr + %td{:width=>"630px", :style=>"padding-top:0px; padding-bottom:20px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px; line-height:20px;"} Each bid costs just $0.75. Bid credits are available in packages of 30, 50, 100 and 200 bids. These bids are pre-paid and credited to your account. Each time you place a bid, one bid credit is deducted from your account. Also, up to 30 seconds is added to the auction timer each time someone bids. This is similar to the “Going once…Going twice…SOLD” approach of traditional auctions, which gives other bidders a chance to make a higher bid if they wish. +%tr + %td{:width=>"630px", :style=>"padding-top:0px; padding-bottom:20px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px; line-height:20px;"} You win the auction if you are the highest bidder when the timer reaches zero. To redeem your win, you simply pay the final auction price plus shipping. If you do not win, the bids you have placed on the auction will not be returned to your account; however, we offer the “Buy Now” feature on most auctions! This feature allows you to use the bids you spent on an auction to buy the same item at a discounted price. See example below: +%tr + %td{:width=>"630px", :style=>"padding-top:0px; padding-bottom:20px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px; line-height:20px;"} Say you placed 40 bids (or $30 worth) on a $50 item, but another bidder wins the auction. Through “Buy Now” you are given the opportunity to purchase the product for its retail value of $50 minus the $30 you spent in bids. Thus, in this example you would be able to buy the item for just $20. +%tr + %td{:width=>"630px", :style=>"padding-top:0px; padding-bottom:20px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px; line-height:20px;"} For more information, see #{ link_to "our rewards page", rewards_url } +%tr + %td{:width=>"630px", :style=>"padding-top:0px; padding-bottom:20px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px; line-height:20px; font-weight:bold;"} Confirm Your Account: +%tr + %td{:width=>"630px", :style=>"padding-top:0px; padding-bottom:20px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px; line-height:20px;"} Please visit the following link within 24 hours to verify your e-mail address: +%tr + %td{:width=>"630px", :style=>"padding-top:0px; padding-bottom:20px; text-align:left;"} + %a{:href => new_activation_url(:code => @account.single_access_token), :style => "color:#EF7A25;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#EF7A25; font-size:13px; line-height:20px;"} + = new_activation_url :code => @account.single_access_token +%tr + %td{:width=>"630px", :style=>"padding-top:0px; padding-bottom:20px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px; line-height:20px;"} An additional e-mail has been sent to you with the same link in case you miss it here! +%tr + %td{:width=>"630px", :style=>"padding-top:0px; padding-bottom:20px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px; line-height:20px; font-weight:bold;"} Additional Questions or Concerns? \ No newline at end of file diff --git a/app/views/customer_mailer/won_auction.html.haml b/app/views/customer_mailer/won_auction.html.haml new file mode 100644 index 0000000..c2c852c --- /dev/null +++ b/app/views/customer_mailer/won_auction.html.haml @@ -0,0 +1,16 @@ +- content_for :subject, "You Won: #{@auction.product.name}" + +%tr + %td{:width=>"630px", :style=>"padding-top:0px; padding-bottom:20px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px; line-height:20px; font-weight:bold;"} CONGRATULATIONS YOU WON! +%tr + %td{:width=>"630px", :style=>"padding-top:0px; padding-bottom:20px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px; line-height:20px;"} Redeem your #{@auction.product.name} by following the link below: +%tr + %td{:width=>"630px", :style=>"padding-top:0px; padding-bottom:20px; text-align:left;"} + %a{:href => auction_url(@auction), :style => "color:#EF7A25;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#EF7A25; font-size:13px; line-height:20px;"} + Click here to claim your win! +%tr + %td{:width=>"630px", :style=>"padding-top:0px; padding-bottom:20px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px; line-height:20px;"} If you have not already paid for this auction, please make sure to do so within the next #{time_ago_in_words(@auction.ending_at + Rails.configuration.won_auction_expiration)}. diff --git a/app/views/invitations/index.html.haml b/app/views/invitations/index.html.haml new file mode 100644 index 0000000..e8a39af --- /dev/null +++ b/app/views/invitations/index.html.haml @@ -0,0 +1,42 @@ +#invites-page + %h2.invitations Invitations + #invites-tabs + %ul + %li#invite-friends-tab.selected Invite Friends + %li#your-invites-tab Your Invites + #invite-friends + %p.invite-explanation For every friend you invite, you will receive 20 free bids after their first purchase. + = form_for @invitation do |f| + - if @invitation.errors.any? + #errorExplanation + %p Oops, please correct the following items to proceed: + %ul + - @invitation.errors.full_messages.each do |msg| + %li= msg + %p.field.clearfix + = f.label :name, "Your Name:" + = f.text_field :name + %p.field.clearfix + = f.label :emails, "Send Invites To:" + = f.text_field :emails + %span separate emails using commas + %p.field.clearfix + = f.label :message, "Personalized Message:" + = f.text_area :message + %p.actions.clearfix + = f.submit "Submit", :class => "button" + %p.link-explanation Below is your personal invitation link. Share it on Facebook/Twitter or copy & paste into your emails. + %p.invitation-link= new_account_url :u => current_user.username, :secure => true + #your-invites + %table + %tr + %th.username Username + %th.join-date Join Date + %th.made-purchase Made Purchase? + %th.bonus-bids Bonus Bids + - current_user.children.each do |u| + %tr + %td= u.username + %td= u.created_at.to_s :default + %td= u.has_purchased ? "yes" : "no" + %td= u.has_purchased ? "+20 bids" : "" \ No newline at end of file diff --git a/app/views/landings/_ended.html.haml b/app/views/landings/_ended.html.haml new file mode 100644 index 0000000..ca76a07 --- /dev/null +++ b/app/views/landings/_ended.html.haml @@ -0,0 +1,3 @@ +/ Each auction object is called "ended"! +%tr + %td= link_to ended.product.name, ended \ No newline at end of file diff --git a/app/views/landings/_upcoming.html.haml b/app/views/landings/_upcoming.html.haml new file mode 100644 index 0000000..a8ca425 --- /dev/null +++ b/app/views/landings/_upcoming.html.haml @@ -0,0 +1,37 @@ +%tr + %td + .product-container.clearfix[upcoming]{:class=> auction_classes(upcoming)} + .title + %h3= link_to upcoming.product.name, upcoming + %p Retail Value: #{number_to_currency upcoming.retail_price} + .image + = link_to image_tag(upcoming.product.main_picture.url(:thumb), size: "70x65"), upcoming + .bid-increment.hasTooltip{:title => increment_title(upcoming)} + .sold-overlay + = link_to upcoming.product.name, upcoming + .timer-container + .upcoming-timer loading... + .winner-text Winner! + .ended-text Ended! + %span.timer-reset-clock.hasTooltip{:title => timer_title(upcoming)} + .price-container + %span.upcoming-price= number_to_currency upcoming.going_price + .last-bidder-container + %span.upcoming-last-bidder= bidder upcoming.username(@winners) + .buttons + .main + .bid-button + - if logged_in? + = form_tag auction_bids_path(upcoming), :id => upcoming.id, :remote => true do + - if current_user.id == upcoming.account_id + = submit_tag "Bid", :class => "button", :disabled => true, :style => "background-position: 0 -120px" + - else + = submit_tag "Bid", :class => "button" + - elsif controller_name == "landings" + %a(href="#form-landing" class="registration button") + - else + = link_to "Login", new_session_path, :class => "login button" + .winner-button= link_to "Checkout", new_order_path(:buyable => upcoming.id, :kind => :upcoming), :class => "button" + .loser-button= link_to "Learn More", auction_path(upcoming, :upcoming_registration => true), :class => "button" + - if upcoming.beginner? + .upcoming-type-title-area.hasTooltip{:title => "Newcomers should try a beginner upcoming and learn how to bid against other newbies.
Same bargains, less competition!"} \ No newline at end of file diff --git a/app/views/landings/active.html.haml b/app/views/landings/active.html.haml new file mode 100644 index 0000000..5046ecd --- /dev/null +++ b/app/views/landings/active.html.haml @@ -0,0 +1,67 @@ +- content_for :title, "#{@auction.product.name} going for just #{number_to_currency @auction.going_price} at FirstBargain.com. Auction closes in #{time_ago_in_words @auction.ending_at}!" +- content_for :description, @auction.product.summary +- content_for :extra_headers do + :javascript + RETAIL_PRICE = #{@auction.retail_price}; + PRICE_INCREMENT = #{@auction.price_increment}; + TIMER_RESET = #{@auction.timer_reset}; + var SOURCE = "details"; + poller([#{@auction.id}], true); + +#auction-details + .wrapper.ad-landing-page[@auction] + %table.product-name + %tr + %td + %h2= @product.name + %td#add-to-watchlist= link_to "Watch", bookmarks_path(:auction_id => @auction.id), :method => :post, :class => "button" + .clearfix{:class => auction_classes(@auction)} + #main-auction-grid + .block-first.clearfix + .product-images + #viewer= image_tag(@product.main_picture.url(:medium), size: "280x260") + %ul#gallery.clearfix + - @product.pictures.each do |p| + %li[p] + = image_tag(p.data.url(:thumb), size: "70x65") + :javascript + registerRollover("#{dom_id p}","#{p.data.url :medium}"); + = render 'auctions/runningnumbers' + = render 'auctions/endnumbers' + #product-description + %h2 Product Description + = simple_format @product.description + #secondary-auction-grid + #registration-form + = render "accounts/form" + .block= render 'auctions/buynow' + .wrapper + #social-media.clearfix + %p Share this: + %ul.left.clearfix-auto + %li= facebook_share_auction @auction + %li + .wrapper + #guarantee + .fb-guarantee= image_tag "text/fb-guarantee.gif" + %ul + %li Full refund on unused bid credits + %li Safe and fair auction environment + %li Risk-free rewards program + %li All items brand new & 100% authentic + %li 14-day return policy + %li.learn-more= link_to image_tag("text/product-description-learn-more.gif"), guarantee_path + + // SHIPPING INFORMATION + - unless @auction.product.bid_pack? + .shipping-information.clearfix + .title Shipping Information + .delivery-cost Delivery Cost: #{ shipping_price @product } + .return-policy + Return Policy: + - if [12,13,14,15,28,29].include? @auction.product.category_id + Gift cards are not eligible for returns + - else + Return within 14 days for any reason + .questions Any Questions? #{ link_to "Contact Us", contact_path } += render 'auctions/auction-overlays' diff --git a/app/views/landings/category.html.haml b/app/views/landings/category.html.haml new file mode 100644 index 0000000..489ebff --- /dev/null +++ b/app/views/landings/category.html.haml @@ -0,0 +1,17 @@ +- content_for :extra_headers do + :javascript + var SOURCE = "homepage"; + poller(#{auction_ids @upcoming, @auction}, false, #{auction_prices @upcoming, @auction}); + +%h2 Upcoming +%table + = render :partial => "upcoming", :collection => @upcoming +%h2 Main +- if @auction.finished? + = render :file => "landings/finished" +- else + = render :file => "landings/active" +%h2 Ended +%table + = render :partial => "ended", :collection => @ended + \ No newline at end of file diff --git a/app/views/landings/finished.html.haml b/app/views/landings/finished.html.haml new file mode 100644 index 0000000..c9c4ca0 --- /dev/null +++ b/app/views/landings/finished.html.haml @@ -0,0 +1,111 @@ +#auction-details + .wrapper.history-page.ad-landing-page[@auction] + %table.product-name + %tr + %td + %h2= @auction.product.name + .auction.clearfix{:class => auction_classes(@auction)} + #main-auction-grid + .block-first.clearfix + .product-images + #viewer= image_tag(@product.main_picture.url :medium) + %ul#gallery.clearfix + - @product.pictures.each do |p| + %li[p] + = image_tag(p.data.url(:thumb), size: "70x65") + :javascript + registerRollover("#{dom_id p}","#{p.data.url :medium}"); + .auction-ended + %table.auction-numbers + %tr.winner + %td.alignC(colspan="2") + %p + Winner: #{ bidder @auction.username, true } + + %tr.price + %td.label Auction Price: + %td.value + %span.auction-price= number_to_currency @auction.going_price + %tr.credits-used + %td.label Paid bids placed by winner (#{ @winner_investment.credits_used }): + %td.value= number_to_currency @winner_investment.amount + %tr.bonuses-used + %td.label Bonus bids placed by winner (#{@winner_investment.bonuses_used}): + %td.value $0.00 + %tr.total-paid + %td.label Total paid by winner: + %td.value= number_to_currency @auction.total_winner_price + %tr.shipping + %td.label Shipping & Handling: + %td.value +#{shipping_price @product} + %tr.retail + %td.alignC(colspan="2") Retail Value: #{ number_to_currency @auction.retail_price } + %tr.discount + %td.alignC(colspan="2") #{buy_now_percentage @winner_investment, @auction} Off + %tr.ended-text + %td.alignC(colspan="2") Auction Ended + %tr.time + %td.alignC(colspan="2") + #{ @auction.ending_at.to_s :auction } + - if @auction.won_by? current_user + .winner-button + %p.text.blue Congratulations! You've won! + - if @auction.redeemed + %p.redeemed Thanks for redeeming this item. + - elsif @auction.redemption_expired? + %p.redeemed Sorry, you can no longer redeem this item. + - else + %p= link_to "Checkout", new_order_path(:buyable => @auction.id, :kind => :auction), :class => "button" + - else + .loser-button + %p.text Check out our other live auctions: + %p= link_to "Home", root_path, :class => "button" + #product-description + %h2 Product Description + = simple_format @product.description + #secondary-auction-grid + //BID HISTORY/ASSISTANT OR REGISTRATION FORM + - if logged_in? + .block + #auction-bid-history + #bid-history-wrapper + %table#bid-history + %thead + %th.username User + %th.price Price + %th.time Time + %tbody + = render @auction.recent_bids + .block= render 'auctions/buynow' + - else + #registration-form + = render "accounts/form" + .wrapper + #social-media.clearfix + %p Share this: + %ul.left.clearfix-auto + %li= facebook_share_auction @auction + %li + .wrapper + #guarantee + .fb-guarantee= image_tag "text/fb-guarantee.gif" + %ul + %li Full refund on unused bid credits + %li Safe and fair auction environment + %li Risk-free rewards program + %li All items brand new & 100% authentic + %li 14-day return policy + %li.learn-more= link_to image_tag("text/product-description-learn-more.gif"), guarantee_path + + // SHIPPING INFORMATION + - unless @auction.product.bid_pack? + .shipping-information.clearfix + .title Shipping Information + .delivery-cost Delivery Cost: #{ shipping_price @product } + .return-policy + Return Policy: + - if [12,13,14,15,28,29].include? @auction.product.category_id + Gift cards are not eligible for returns + - else + Return within 14 days for any reason + .questions Any Questions? #{ link_to "Contact Us", contact_path } \ No newline at end of file diff --git a/app/views/landings/promo.html.haml b/app/views/landings/promo.html.haml new file mode 100644 index 0000000..e5b4724 --- /dev/null +++ b/app/views/landings/promo.html.haml @@ -0,0 +1,95 @@ +!!! 5 +%html + %head + = render 'layouts/meta' + = render 'layouts/og' + = include_stylesheets :base + = csrf_meta_tag + = javascript_include_tag :cdn + = include_javascripts :base + :javascript + var SOURCE = "homepage"; + var USER_LOGIN = #{user_login}; + var USER_ID = #{user_id}; + poller(#{auction_ids @auctions}, false, #{auction_prices @auctions}); + = render 'layouts/ie' + %body#promo-landing-page.penny-promo + #main-wrapper + #container + #header.clearfix + #logo-area.clearfix-auto + %h1#logo + #social-media-affiliate + .clearfix-auto + .facebook-like + %script(src="http://connect.facebook.net/en_US/all.js#xfbml=1" type="text/javascript") + + #top-login + - if logged_in? + #login-tab + %ul#user-credits-overview + %li Welcome #{ link_to current_user.username, account_path } + %li Bids: #{ current_user.credits } + %li Bonus Bids: #{ current_user.bonuses } + %li MemberPoints: #{ current_user.points } + %li.last= link_to "My Account", account_path + %span#button + %span#logout-node + %span + = link_to "Logout", session_path, :method => :delete + - else + #login-tab + %span#have-account Already have an account? + %span#button + %span#toggle-node + %span Sign In + #login-body + .wrapper + = form_for AccountSession.new, :url => session_path(:secure => true) do |f| + %p.field + = f.label :username + = f.text_field :username + %p.field + = f.label :password + = f.password_field :password + .login-remember-me-wrapper.clearfix + %p.actions.signin + = f.submit "Sign In", :id => "login-submit" + %p.actions.remember-me + = f.check_box :remember_me + = f.label :remember_me + .login-forgot-password + Forgot your password? #{ link_to "Click here", new_password_reset_path } + #penny-head + #content.padded + #splash + #firstbargain-vs-ebay + #penny-revolution + #firstbargain-savings + #savings-banner + #scroll-out + %a(href="#form-landing") + =image_tag "promo/scroll-out.jpg" + #ended-auctions-text + #ended-auctions + #live-auctions-text + #live-auctions + #auctions-index + %table#main-auctions + %tr + = render @auctions + = fill_grid @auctions, "auction", 4 + = render 'auctions/auction-overlays' + #thousands-satisfied + #registration-wrapper.clearfix + %a(name="form-landing") + #testimonials + #registration-form + .header + .body + = render "accounts/form" + .footer + #penny-quotes + #container-bottom + = render 'layouts/footer' + = render 'layouts/msc' \ No newline at end of file diff --git a/app/views/layouts/_footer.html.haml b/app/views/layouts/_footer.html.haml new file mode 100644 index 0000000..a268b52 --- /dev/null +++ b/app/views/layouts/_footer.html.haml @@ -0,0 +1,41 @@ +- unless supported_browser? + #unsupported-browser + You are running an older version of Internet Explorer. For better performance, upgrade to a newer version of Internet Explorer: Internet Explorer 8 or 9 + +#footer-wrapper + #footer.clearfix + %ul#merchant-icons + + %li + %div=image_tag 'footer/visa.gif' + %li + %div=image_tag 'footer/mc.gif' + %li.external + %div + / PayPal Logo + %a{:class=>"popup", :href=>"https://www.paypal.com/cgi-bin/webscr?cmd=xpt/Marketing/popup/OLCWhatIsPayPal-outside" } + = image_tag 'footer/paypal.gif' + -# + %li.external + %div + / (c) 2005, 2010. Authorize.Net is a registered trademark of CyberSource Corporation + %script var ANS_customer_id="ac730586-9939-4301-a9a5-0a1a8c2c1d88"; + %script{:src => "//verify.authorize.net/anetseal/seal.js"} + %li.external + %div + %a{:class=>"popup", :href=>"https://trustsealinfo.verisign.com/splash?form_file=fdf/splash.fdf&dn=www.firstbargain.com&lang=en" } + = image_tag 'footer/verisign.png' + %ul + %li + %div= link_to "About Us", about_path + %li + %div= link_to "F.A.Q.", faq_path + %li + %div= link_to "Terms of Service", tos_path + %li + %div= link_to "Privacy Policy", privacy_path + %li + %div= link_to "Return Policy", returns_path + %li + %div= link_to "Contact Us", contact_path + %p Copyright © 2011 FirstBargain.com. \ No newline at end of file diff --git a/app/views/layouts/_header.html.haml b/app/views/layouts/_header.html.haml new file mode 100644 index 0000000..6c901f2 --- /dev/null +++ b/app/views/layouts/_header.html.haml @@ -0,0 +1,60 @@ +#top-login + - if logged_in? + #login-tab + %ul#user-credits-overview + %li Welcome #{ link_to current_user.username, account_path } + %li Bids: #{ current_user.credits } + %li Bonus Bids: #{ current_user.bonuses } + %li.last= link_to "My Account", account_path + %span#button + %span#logout-node + %span + = link_to "Logout", session_path, :method => :delete + - else + #login-tab + %span#have-account Already have an account? + %span#button + %span#toggle-node + %span Sign In + #login-body + .wrapper + = form_for AccountSession.new, :url => session_path(:secure => true) do |f| + %p.field + = f.label :username + = f.text_field :username + %p.field + = f.label :password + = f.password_field :password + .login-remember-me-wrapper.clearfix + %p.actions.signin + = f.submit "Sign In", :id => "login-submit" + %p.actions.remember-me + = f.check_box :remember_me + = f.label :remember_me + .login-forgot-password + Forgot your password? #{ link_to "Click here", new_password_reset_path } +#header.clearfix + #logo-area.clearfix-auto + %h1#logo= link_to_affiliate + #social-media-affiliate + - unless request.ssl? + .clearfix-auto + .facebook-like + %script(src="http://connect.facebook.net/en_US/all.js#xfbml=1" type="text/javascript") + + .powered-by + #navigation.clearfix + = tabs_tag :open_tabs => {:class => "clearfix"}, :builder => MenuTabBuilder do |t| + %li.invite-link + = link_to "Invite Friends", invitations_path, :class => "button" + %li.facebook-link + = link_to "Our Facebook Page", "http://www.facebook.com/FirstBargain", :rel => "nofollow", :target => "_blank", :class => "button" + = t.faq "Help", faq_path, :class => "last" + = t.tutorial "How It Works", tutorial_path + - if logged_in? + = t.bids "Buy Bids", bids_path + - else + = t.register "Register", new_account_path + = t.store "Members Shop", products_path + = t.winners "Winners", winners_auctions_path + = t.auctions "Auctions", auctions_path \ No newline at end of file diff --git a/app/views/layouts/_ie.html.haml b/app/views/layouts/_ie.html.haml new file mode 100644 index 0000000..b67d2c4 --- /dev/null +++ b/app/views/layouts/_ie.html.haml @@ -0,0 +1,42 @@ +/[if IE] + :css + .clearfix { + zoom: 1; + *display: block; + } + .clearfix-auto { + display: -moz-inline-stack; + display: inline-block; + zoom: 1; + *display: inline; + } +/[if IE 8] + :css + #new-order #credit-card-form, #new-order #paypal-form { + min-height: 900px; + height: auto!important; + } +/[if IE 7] + :css + #register-page #account_terms_of_service { + margin: 0; + padding: 0; + } + #register-page .field label[htmlFor="account_terms_of_service"] { + width: 380px; + } + form .field label[htmlFor="account_session_remember_me"], form .field label[htmlFor="shipping-address-toggle-node"] { + float: none; + width: auto; + line-height: 1.0em; + text-align: left; + text-transform: none; + margin: 0; + } + select { + padding: 0.6em; + font-size: 12px; + font-weight: bold; + border: 1px solid #CDCED0; + color: #808080; + } \ No newline at end of file diff --git a/app/views/layouts/_meta.html.haml b/app/views/layouts/_meta.html.haml new file mode 100644 index 0000000..a2c91f5 --- /dev/null +++ b/app/views/layouts/_meta.html.haml @@ -0,0 +1,3 @@ +%title= yield_for :title, "First Bargain - Your first stop to bargain shopping. Save up to 90% at FirstBargain.com" +%meta{:name => "description", :content => yield_for(:description, "Bid to win huge bargains up to 90% off! Save on popular electronics, fashion, and home products. Best deals on the internet - Blowout sales every day!")} +%meta{:name => "keywords", :content => "firstbargain, first bargain, bargain, bargains, cheap, clearance, blowout sale, discount, discounts, ipod, ipad, hdtv, camera, laptop, mp3 player, gps, ps3, xbox, wii, kindle"} diff --git a/app/views/layouts/_msc.html.haml b/app/views/layouts/_msc.html.haml new file mode 100644 index 0000000..bd8e5ca --- /dev/null +++ b/app/views/layouts/_msc.html.haml @@ -0,0 +1,11 @@ +/ Google Analytics AJAX Tracker +:javascript + var _gaq = _gaq || []; + _gaq.push(['_setAccount', 'UA-17750582-2']); + _gaq.push(['_trackPageview']); + + (function() { + var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; + ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; + var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); + })(); \ No newline at end of file diff --git a/app/views/layouts/_og.html.haml b/app/views/layouts/_og.html.haml new file mode 100644 index 0000000..0ba3496 --- /dev/null +++ b/app/views/layouts/_og.html.haml @@ -0,0 +1,17 @@ +/ FACEBOOK OPENGRAPH + + +- if @auction + - unless request.ssl? + = javascript_include_tag "http://static.ak.fbcdn.net/connect.php/js/FB.Share" + + %meta{:property =>"og:description", :content => "This brand new #{@auction.product.name} is going for #{number_to_currency @auction.going_price} on FirstBargain.com!"} + %meta{:property => "og:url", :content => auction_url(@auction)} + %meta{:property => "og:image", :content => picture_url(@auction)} + +- else + + + %meta{:property => "og:url", :content => request.url} + + diff --git a/app/views/layouts/accounts.html.haml b/app/views/layouts/accounts.html.haml new file mode 100644 index 0000000..f607458 --- /dev/null +++ b/app/views/layouts/accounts.html.haml @@ -0,0 +1,41 @@ +!!! 5 +%html + %head + = render 'layouts/meta' + = include_stylesheets :base + = javascript_include_tag :cdn + = include_javascripts :base + = csrf_meta_tag + :javascript + USER_LOGIN = #{user_login}; + USER_ID = #{user_id}; + = load_affiliate_stylesheet + = render 'layouts/ie' + = yield :extra_headers + %body + #xhr-status + %p.warning Please check your Internet connection. + %p Your computer is taking too long to get auction updates. + #bid-status + #main-wrapper + #container + = render 'layouts/header' + #content.padded + #account-page.sidebar.clearfix + #main-menu + = tabs_tag :namespace => :sidebar do |t| + = t.overview "Overview", account_path, :class => "first" + = t.watchlist "Watchlist", bookmarks_path + = t.orders "Orders & Account History", orders_path + = t.settings "Account Settings", edit_account_path + = t.coupons "Redeem Coupon", new_coupon_path + = t.invitations "Invitations", invitations_path, :class => "last" + .current-page + - if notice + %p.notice= notice + - elsif alert + %p.alert= alert + = yield + #container-bottom + = render 'layouts/footer' + = render 'layouts/msc' \ No newline at end of file diff --git a/app/views/layouts/admin.html.haml b/app/views/layouts/admin.html.haml new file mode 100644 index 0000000..fde2045 --- /dev/null +++ b/app/views/layouts/admin.html.haml @@ -0,0 +1,36 @@ +!!! 5 +%html + %head + = render 'layouts/meta' + = include_stylesheets :admin + = javascript_include_tag :cdn + = include_javascripts :base + = javascript_include_tag 'protovis' + = csrf_meta_tag + %meta(name="ROBOTS" content="NOINDEX, NOFOLLOW") + = load_affiliate_stylesheet + = render 'layouts/ie' + %body#admin + #main-wrapper + #container + #main-menu.clearfix + %ul + %li= link_to "Auctions", admin_auctions_path + %li= link_to "Products", admin_products_path + %li= link_to "Orders", admin_orders_path + %li= link_to "Accounts", admin_accounts_path + %li= link_to "Categories", admin_categories_path + %li= link_to "Coupons", admin_coupons_path + %li= link_to "Online", online_admin_accounts_path + %li= link_to "Analytics", admin_analytics_path + %li.last= link_to "Site", root_path + #content.padded + #admin-current-page + #export-as-xml #{link_to "Export as XML", url_for(:format => :xml)} (experimental, doesn't work for every page yet) + - if notice + %p.notice= notice + - elsif alert + %p.alert= alert + = yield + #container-bottom + = render 'layouts/msc' diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml new file mode 100644 index 0000000..ac03e48 --- /dev/null +++ b/app/views/layouts/application.html.haml @@ -0,0 +1,52 @@ +!!! 5 +%html + %head + = render 'layouts/meta' + = render 'layouts/og' + = include_stylesheets :base + = javascript_include_tag :cdn + = include_javascripts :base + = csrf_meta_tag + :javascript + var USER_LOGIN = #{user_login}; + var USER_ID = #{user_id}; + = yield :extra_headers + = load_affiliate_stylesheet + = render 'layouts/ie' + %body + #xhr-status + %p.warning Please check your Internet connection. + %p Your computer is taking too long to get auction updates. + #bid-status + - if logged_in? + #user-credits-main + %ul + %li + %div + %span.latency.conn-good.hasTooltip{:title=>"Your internet connection is good"} + %li + %div + %span.label Bid Credits: + %strong.credits-count= current_user.credits + = image_tag "labels/bid-credits.png" + %li + %div + %span.label Bonus Bids: + %strong.bonuses-count= current_user.bonuses + = image_tag "labels/bonus-credits.png" + %li.last + %div + %span.buy-bids= link_to "Buy Bids", bids_path, :class => "button" + #main-wrapper + #container + = render 'layouts/header' + #content.padded + - if notice + %p.notice= notice + - elsif alert + %p.alert= alert + = yield + #container-bottom + = render 'layouts/footer' + = render 'layouts/msc' + diff --git a/app/views/layouts/basic.html.haml b/app/views/layouts/basic.html.haml new file mode 100644 index 0000000..def596c --- /dev/null +++ b/app/views/layouts/basic.html.haml @@ -0,0 +1,6 @@ +!!! 5 +%html + %head + %title First Bargain + %body + = yield diff --git a/app/views/layouts/howtoplay.html.haml b/app/views/layouts/howtoplay.html.haml new file mode 100644 index 0000000..e094279 --- /dev/null +++ b/app/views/layouts/howtoplay.html.haml @@ -0,0 +1,30 @@ +!!! 5 +%html + %head + = render 'layouts/meta' + = csrf_meta_tag + = include_stylesheets :base + = javascript_include_tag :cdn + = include_javascripts :base + = load_affiliate_stylesheet + = render 'layouts/ie' + %body#tutorial + #main-wrapper + #container + = render 'layouts/header' + #content.padded.clearfix-auto + #flat-page + #tips-rules-wrapper + = link_to "Bidding Tips", tips_path, :class => "button", :id => "bidding-tips-link" + = link_to "Site Rules", rules_path, :class => "button", :id => "site-rules-link" + %h2.how-to-play How It Works + #how-to-menu + = tabs_tag :namespace => :sidebar do |t| + = t.play "How it Works", tutorial_path, :id => "auctions-tab" + = t.rewards "Member Rewards", rewards_path, :id => "rewards-tab" + = t.guarantee "First Bargain Guarantee", guarantee_path, :id => "guarantee-tab" + .current-page + = yield + #container-bottom + = render 'layouts/footer' + = render 'layouts/msc' \ No newline at end of file diff --git a/app/views/layouts/maintenance.html.haml b/app/views/layouts/maintenance.html.haml new file mode 100644 index 0000000..cad0964 --- /dev/null +++ b/app/views/layouts/maintenance.html.haml @@ -0,0 +1,60 @@ +!!! 5 +%html + %head + %title FirstBargain.com - Sorry, we'll be back in a few... + %meta(name="ROBOTS" content="NOINDEX, NOFOLLOW") + :css + html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, h7, p, blockquote, pre, + a, abbr, acronym, address, big, cite, code, del, dfn, font, img, ins, kbd, q, s, samp, + sub, sup, tt, var, dd, dl, dt, li, ol, ul, form, fieldset, input, textarea, label, + table, legend, caption, tbody, tfoot, thead, tr, th, td { + font-family: inherit; + font-weight: inherit; + font-style: inherit; + font-size: 100%; + text-align: left; + margin: 0; + padding: 0; + } + body { + color: #808080; + font-family: Helvetica, Helvetica Neue, Arial, sans-serif; + font-size: 13px; + } + #wrapper { + margin: 55px auto; + height: 340px; + width: 520px; + padding: 160px 200px 0 80px; + background: url(//www.firstbargain.com/images/server-status/maintenance.jpg) no-repeat; + } + h1 { + font-size: 1.5em; + margin-bottom: 35px; + color: #EF7A25; + } + p { + margin-bottom: 15px; + } + a { + color: #EF7A25; + text-decoration: none; + } + a:hover { + text-decoration: underline; + cursor: pointer; + } + #signature { + padding-top: 20px; + } + #signature em { + font-size: 1.1em; + } +%body + #wrapper + %h1 Sorry, we'll be back in a few... + %p FirstBargain.com is temporarily closed for routine website maintenance as we work to bring you a better auction experience. + %p We apologize for any inconvenience this may cause you. If you have any questions, please feel free to contact us. + #signature + %p Happy bidding! + %p First Bargain Team diff --git a/app/views/layouts/notifier.html.haml b/app/views/layouts/notifier.html.haml new file mode 100644 index 0000000..2a4e026 --- /dev/null +++ b/app/views/layouts/notifier.html.haml @@ -0,0 +1,49 @@ +%table{:width =>"100%", :border=>"0", :cellpadding=>"0", :cellspacing=>"0"} + %tbody + %tr + %td{:align=>"center", :bgcolor=>"#ffa524", :style=>"padding-top:30px; padding-bottom:20px;"} + / TOP WRAPPER + %table{:border=>"0", :cellpadding=>"0", :cellspacing=>"0", :width=>"670px", :height=>"5px"} + %tr + %td{:width=>"670px", :height=>"5px"}=image_tag 'http://www.firstbargain.com/images/email/v030311/top-wrap.png', :width=>"670px", :height=>"5px", :style=>"display:block;", :alt=>"FirstBargain.com Top Wrapper" + / WRAPPER CONTAINER + %table{:width => "670px", :border=>"0", :cellpadding=>"0", :cellspacing => "0"} + %tr + %td{:width=>"20px", :bgcolor=>"#FFFFFF"} + %td{:width=>"630px", :bgcolor=>"#FFFFFF", :align=>"center"} + / HEADER + %table{:width=>"630px", :height=>"60px", :border=>"0", :cellpadding=>"0", :cellspacing=>"0"} + %tr + %td{:width=>"195px", :height=>"60px"}=image_tag 'http://www.firstbargain.com/images/email/v030311/logo.gif', :width=>"195px", :height=>"60px", :style=>"display:block;", :alt=>"FirstBargain.com Logo" + %td{:width=>"475px", :height=>"60px"} + / BODY + %table{:width=>"630px", :border=>"0", :cellpadding=>"0", :cellspacing=>"0"} + %tr + %td{:width=>"630px", :style=>"padding-top:20px; padding-bottom:20px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px; line-height:20px;"} Dear #{@account.username}, + = yield + %tr + %td{:width=>"630px", :style=>"padding-top:0px; padding-bottom:20px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px; line-height:20px;"} + If you have any questions, please contact us at support@firstbargain.com or by simply replying to this email. We make every effort to respond to all customer inquiries within 24-48 hours. + %tr + %td{:width=>"630px", :style=>"padding-top:0px; padding-bottom:10px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#545454; font-size:13px; line-height:20px;"} Sincerely, + %tr + %td{:width=>"630px", :style=>"padding-top:0px; padding-bottom:40px; text-align:left;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#808080; font-style:italic; font-size:22px; line-height:20px;"} First Bargain Team + / NAVIGATION + %table{:width=>"630px", :height=>"35px", :border=>"0", :cellpadding=>"0", :cellspacing=>"0", :background=>"http://www.firstbargain.com/images/email/v030311/nav-bar.png"} + %tr + %td{:width=>"630px", :height=>"35px", :align=>"center", :style=>"text-align:center;"} + %span{:style => "font-family:Helvetica,Arial,sans-serif; color:#FFFFFF; font-size:15px;"} + #{link_to "Home", auctions_url, :style=>"font-family:Helvetica,Arial,sans-serif; color:#FFFFFF; font-size:15px; text-decoration:none; padding-left:12px; padding-right:12px;"} | + #{link_to "Members Shop", products_url, :style=>"font-family:Helvetica,Arial,sans-serif; color:#FFFFFF; font-size:15px; text-decoration:none; padding-left:12px; padding-right:12px;"} | + #{link_to "My Account", account_url, :style=>"font-family:Helvetica,Arial,sans-serif; color:#FFFFFF; font-size:15px; text-decoration:none; padding-left:12px; padding-right:12px;"} | + #{link_to "How It Works", tutorial_url, :style=>"font-family:Helvetica,Arial,sans-serif; color:#FFFFFF; font-size:15px; text-decoration:none; padding-left:12px; padding-right:12px;"} | + #{link_to "Help", faq_url, :style=>"font-family:Helvetica,Arial,sans-serif; color:#FFFFFF; font-size:15px; text-decoration:none; padding-left:12px; padding-right:12px;"} + %td{:width=>"20px", :bgcolor=>"#FFFFFF"} + / BOTTOM WRAPPER + %table{:border=>"0", :cellpadding=>"0", :cellspacing=>"0", :width=>"670px", :height=>"20px"} + %tr + %td{:width=>"670px", :height=>"20px"}=image_tag 'http://www.firstbargain.com/images/email/v030311/bot-wrap.png', :width=>"670px", :height=>"20px", :style=>"display:block;", :alt=>"FirstBargain.com Bottom Wrapper" diff --git a/app/views/layouts/orders.html.haml b/app/views/layouts/orders.html.haml new file mode 100644 index 0000000..abdffaa --- /dev/null +++ b/app/views/layouts/orders.html.haml @@ -0,0 +1,23 @@ +!!! 5 +%html + %head + = render 'layouts/meta' + = csrf_meta_tag + = include_stylesheets :base + = javascript_include_tag :cdn + = include_javascripts :base + = load_affiliate_stylesheet + = render 'layouts/ie' + %body + #main-wrapper + #container + = render 'layouts/header' + #content.padded + - if notice + %p.notice= notice + - if alert + %p.alert= alert + = yield + #container-bottom + = render 'layouts/footer' + = render 'layouts/msc' \ No newline at end of file diff --git a/app/views/layouts/static.html.haml b/app/views/layouts/static.html.haml new file mode 100644 index 0000000..5523c8c --- /dev/null +++ b/app/views/layouts/static.html.haml @@ -0,0 +1,33 @@ +!!! 5 +%html + %head + = render 'layouts/meta' + = csrf_meta_tag + = include_stylesheets :base + = javascript_include_tag :cdn + = include_javascripts :base + = load_affiliate_stylesheet + = render 'layouts/ie' + %body + #main-wrapper + #container + = render 'layouts/header' + #content.padded.clearfix-auto + #flat-page.sidebar + #main-menu + = tabs_tag :namespace => :sidebar, :builder => MenuTabBuilder do |t| + = t.faq "F.A.Q.", faq_path, :class => "first" + = t.rules "Site Rules", rules_path + = t.tos "Terms of Service", tos_path + = t.returns "Refunds & Returns", returns_path + = t.contact "Contact Us", contact_path + = t.about "About Us", about_path, :class => "last" + .current-page + - if notice + %p.notice= notice + - elsif alert + %p.alert= alert + = yield + #container-bottom + = render 'layouts/footer' + = render 'layouts/msc' \ No newline at end of file diff --git a/app/views/orders/_cart.html.haml b/app/views/orders/_cart.html.haml new file mode 100644 index 0000000..82b8526 --- /dev/null +++ b/app/views/orders/_cart.html.haml @@ -0,0 +1,25 @@ +#shopping-cart-numbers + %table + %tr.product + %td(colspan="2") + #{@order.contents} + %tr.image + %td(colspan="2") + %p= order_picture @order + %tr.subtotal + %td.label Subtotal: + %td.value= number_to_currency @order.subtotal + %tr.tax + %td.label Sales Tax: + %td.value= number_to_currency @order.sales_tax + %tr.shipping-handling + %td.label Shipping & Handling: + %td.value= number_to_currency @order.shipping_price + %tr.member-discount + %td.label MemberPoints: + %td.value -#{ @order.point_discount} + %tr.total + %td.label.total Grand Total: + %td.value.total= number_to_currency @order.total_price + %p ** MemberPoints only apply to items purchased from the Members Shop + %p ** For purchases under $2.95, we charge a minimum of $2.95. \ No newline at end of file diff --git a/app/views/orders/_payment_fields.html.haml b/app/views/orders/_payment_fields.html.haml new file mode 100644 index 0000000..0329dc1 --- /dev/null +++ b/app/views/orders/_payment_fields.html.haml @@ -0,0 +1,65 @@ +%h2.payment Payment Options +#payment-tabs + %ul.clearfix + %li#cc-tab.selected Credit Card + %li#pp-tab PayPal +#credit-card-form.clearfix + %p Check out using Visa, MasterCard, or Discover. + -# + #checkout-payments + %p.field + = f.label :first_name + = f.text_field :first_name + %p.field + = f.label :last_name + = f.text_field :last_name + %p.field.cc-type + = f.label :card_type + = f.select :card_type, [["Visa", "visa"], ["MasterCard", "master"]] + = image_tag "cc/visa-mc.gif", :alt => "visa-mastercard" + %p.field + = f.label :card_number + = f.text_field :card_number, :autocomplete => "off" + %p.field.cvv + = f.label :card_verification, "CVV" + = f.text_field :card_verification, :class => "small", :autocomplete => "off" + %p.field + = f.label :card_expires_on, "Expiration" + = f.date_select :card_expires_on, :discard_day => true, :start_year => Date.today.year, :end_year => Date.today.year + 10, :add_month_numbers => true + .separator + #checkout-address + -# + %p.field.address + = f.label :billing_address + = f.text_field :billing_address + %p.field.address + = f.label :billing_address_2, "Address 2" + = f.text_field :billing_address_2 + %p.field + = f.label :billing_city, "City" + = f.text_field :billing_city + .field.clearfix + %p.state + = f.label :billing_state, "State" + = f.select :billing_state, Address::STATES + %p.zip + = f.label :billing_zip, "Zip" + = f.text_field :billing_zip, :size => 5, :maxlength => 5 + %p.field.phone + = f.label :billing_phone + = f.text_field :billing_phone + %p.phone-example e.g. 305-555-0123 + - if @order.requires_shipping? + = render :partial => 'shipping_address_fields', :locals => {:f => f} + %p.action + = f.submit "Confirm Order", :class => "button" + +#paypal-form + = image_tag "text/paypal.png" + %h3 + PayPal is the safer, easier way to pay + %ul + %li Never expose your credit card number. + %li Speed through checkout all over the web. One account, one password - no need to retype your shipping or financial information. + %p.action + = f.submit "Pay with PayPal", :class => "button" \ No newline at end of file diff --git a/app/views/orders/_shipping_address_fields.html.haml b/app/views/orders/_shipping_address_fields.html.haml new file mode 100644 index 0000000..50e714b --- /dev/null +++ b/app/views/orders/_shipping_address_fields.html.haml @@ -0,0 +1,28 @@ +-# + #same-shipping-billing.field.clearfix-auto + = f.check_box :different_shipping, :id => "shipping-address-toggle-node" + = f.label :different_shipping, "I would like to ship my product to a different address.", :for => "shipping-address-toggle-node" +#shipping-address(style="display:block") + %p.field(style="padding-top:10px;") + = f.label :shipping_name, "Recipient Name" + = f.text_field :shipping_name + %p.field.address + = f.label :shipping_address, "Shipping Address" + = f.text_field :shipping_address + %p.field.address + = f.label :shipping_address_2, "Address 2" + = f.text_field :shipping_address_2 + %p.field + = f.label :shipping_city, "City" + = f.text_field :shipping_city + .field.clearfix + %p.state + = f.label :shipping_state, "State" + = f.select :shipping_state, Address::STATES + %p.zip + = f.label :shipping_zip, "Zip" + = f.text_field :shipping_zip, :size => 5, :maxlength => 5 + %p.field.phone + = f.label :shipping_phone, "Shipping Phone" + = f.text_field :shipping_phone + %p.phone-example e.g. 305-555-0123 \ No newline at end of file diff --git a/app/views/orders/confirm.html.haml b/app/views/orders/confirm.html.haml new file mode 100644 index 0000000..97bcb64 --- /dev/null +++ b/app/views/orders/confirm.html.haml @@ -0,0 +1,53 @@ +#confirm-order.clearfix + %h2.confirm-your-order Confirm Your Order + .left-column-1 + = render 'cart' + .right-column-1 + #billing-address.wrapper + %h3 Billing Address + %address + #{@order.billing_name} + %br + #{@order.billing_address} + - if @order.billing_address_2? + %br + #{@order.billing_address_2} + %br + #{@order.billing_city}, #{@order.billing_state}, #{@order.billing_zip} + %br + #{@order.billing_phone} + - if @order.requires_shipping? + #shipping-address.wrapper + %h3 Shipping Address + %address + #{@order.shipping_name} + %br + #{@order.shipping_address} + - if @order.shipping_address_2? + %br + #{@order.shipping_address_2} + %br + #{@order.shipping_city}, #{@order.shipping_state}, #{@order.shipping_zip} + %br + #{@order.shipping_phone} + #credit-card + %h3 Credit Card + %table + %tr + %td.label Name on Card: + %td.value= @order.billing_name + %tr + %td.label Credit Card: + %td.value + - if @order.card_type == "visa" + = image_tag "cc/visa.gif", :class => "cc-img" + - else + = image_tag "cc/mc.gif", :class => "cc-img" + %p.card-number= hide_card_number @order.card_number + %tr + %td.label Expiration Date: + %td.value= @order.card_expires_on.strftime "%m/%Y" + #place-order + %p.tos-agreement By placing your order, you agree to FirstBargain.com's #{link_to "Privacy Policy", privacy_path} and #{link_to "Terms of Service", tos_path}. + = form_for @order, :as => :order, :url => orders_path(:secure => true) do |f| + %p.actions= f.submit "Order Now", :class => "button" \ No newline at end of file diff --git a/app/views/orders/create.js.erb b/app/views/orders/create.js.erb new file mode 100644 index 0000000..4ce31eb --- /dev/null +++ b/app/views/orders/create.js.erb @@ -0,0 +1,12 @@ +<% if @order.invalid? %> +var x = "

There were some problems with what you entered on PayPal:

    " +<% @order.errors.full_messages.each do |msg| %> +x += "
  • <%= msg %>
  • "; +<% end %> +x += "
"; +$("#order-processing").html(x); +<% elsif @order.declined? %> +window.location.replace("../orders/failure"); +<% else %> +window.location.replace("../orders/success"); +<% end %> \ No newline at end of file diff --git a/app/views/orders/failure.html.haml b/app/views/orders/failure.html.haml new file mode 100644 index 0000000..a55b357 --- /dev/null +++ b/app/views/orders/failure.html.haml @@ -0,0 +1,8 @@ +#order-failure + %h2.were-sorry We're sorry + %p Error code: #{@msg} + - if @order.paypal? + %p PayPal has declined the transaction.
Perhaps your PayPal account balance is too low, or your PayPal credit card is not verified. + - else + %p Our credit card processor has declined the transaction.
Perhaps the billing address you provided does not match that of the cardholder's, or the CVV may be incorrect. + %p Please #{link_to "try again", root_path} with a different payment method and contact #{mail_to "support@firstbargain.com", "customer support", :subject => "Billing Help"} if you continue to have problems. \ No newline at end of file diff --git a/app/views/orders/index.html.haml b/app/views/orders/index.html.haml new file mode 100644 index 0000000..cd09333 --- /dev/null +++ b/app/views/orders/index.html.haml @@ -0,0 +1,54 @@ +.block-first + %h2.your-order-history Your order history + #order-history-icon-legend + #account-order-history + %table.order-history-hidden + %tr + %th.date Purchased Date + %th.items Product Description + %th.price Total Price + %th.status Status + - @orders.each do |o| + %tr{:class => o.state} + %td.date= (o.created_at.to_s :order_history).html_safe + %td.items{:class => order_class(o)} + = link_to_order o + %span.order-id Order ID: #{ o.id } + %td.price= number_to_currency o.total_price + %td.status= o.state + #show-void-declined + Show Void & Declined Orders +.block-last + #order-history-key + %h3 What are all the steps in the order process? + %dl + %dt Complete + %dd We have successfully charged your Credit Card or PayPal account. Your bid pack should be credited to your account immediately. + %dt Paid + %dd We have successfully charged your Credit Card or PayPal account. Your order will be processed for shipping. + %dt Shipped + %dd Your order has left our warehouses and is on its way to you. + %dt.hold Processing + %dd We are reviewing this order. + %dt.hold Refunded + %dd Your order has been canceled. Please allow 1 to 2 weeks for the refund to appear on your bank statement. + %dt.error On Hold + %dd Your order is undergoing some changes. + %dt.error Declined + %dd We were unable to charge your Credit Card or PayPal account. If any order is declined, please try again after a few minutes. If you are still having problems, please #{ link_to "contact us", contact_path }. +- if session[:bidpopup] then + - session.delete :bidpopup + #new-bidder-popup + .overlay-popup-toggle= image_tag "msc/close-icon.gif", size: "16x16" + .left= image_tag "msc/glasses-book.jpg" + %p.welcome Welcome to FirstBargain! + %p Here's a few things you need to know to get started: + %ul + %li Each time you bid, one bid will be deducted from your bids account. + %li Also, each time a bid is placed, a maximum of 30 seconds will be added to the clock. This allows time for other bidders to decide if they want to keep bidding or not. Think of an auction, going once... going twice... + %li If you are the last bidder when the clock runs out, you are the winner! Once you have won, you will purchase the product for the ending price of the auction. + %li If you do not win, you will lose the bids you have placed, however, you can use our "Buy Now" option to purchase the item at retail value, and the cash value of the bids you have placed will be discounted from your total ("Buy Now" is available on most products) + %li + %p.right= link_to "Start Bidding!", auctions_path, :class => "button" + We recommend visiting our #{ link_to "tutorial page", tutorial_path } to familiarize yourself with our bidding process before you place your first bid. + diff --git a/app/views/orders/new.html.haml b/app/views/orders/new.html.haml new file mode 100644 index 0000000..f535701 --- /dev/null +++ b/app/views/orders/new.html.haml @@ -0,0 +1,20 @@ +#new-order.orders-page + %h2.my-shopping-cart My Shopping Cart + .clearfix + = form_for @order, :as => :order, :url => confirm_orders_path(:secure => true), :html => {:class => "address-form"} do |f| + - if @order.errors.any? + #errorExplanation + %p Oops, please correct the following items to proceed: + %ul + - @order.errors.full_messages.each do |msg| + %li= msg + .left-column-4 + #product-shipping + = render 'cart' + #us-shipping-only= image_tag ("msc/us-flag.gif") + .right-column-4 + #checkout-payments + = f.hidden_field :kind, :value => kind(@order) + = f.hidden_field :buyable, :value => buyable(@order) + = f.hidden_field :gateway, :value => "authorize" + = render :partial => 'payment_fields', :locals => {:f => f} \ No newline at end of file diff --git a/app/views/orders/paypal.html.haml b/app/views/orders/paypal.html.haml new file mode 100644 index 0000000..23a2140 --- /dev/null +++ b/app/views/orders/paypal.html.haml @@ -0,0 +1,35 @@ +#confirm-order.orders-page.clearfix + %h2.confirm-your-order Confirm Your Order + .left-column-1 + = render 'cart' + .right-column-1 + #billing-address.wrapper + %h3 Billing Address + %address + %em Billing info. confirmed by PayPal + #shipping-address.wrapper + %h3 Shipping Address + %address + - if @order.requires_shipping? + #{@order.shipping_name} + %br + #{@order.shipping_address} + - if @order.shipping_address_2? + %br + #{@order.shipping_address_2} + %br + #{@order.shipping_city}, #{@order.shipping_state}, #{@order.shipping_zip} + %br + #{@order.shipping_phone} + - else + No shipping is required for your purchase. + #paypal + %h3 Payment Type + %p PayPal + #place-order + %p.tos-agreement By placing your order, you agree to FirstBargain.com's #{link_to "Privacy Policy", privacy_path} and #{link_to "Terms of Service", tos_path}. + = form_for @order, :url => orders_path(:secure => true), :remote => true do |f| + %p.actions= f.submit "Order Now", :class => "button", :disable_with => "Processing..." + #order-processing{:style => "display: none"} + %p Your order is being processed. You will be redirected soon. + = image_tag 'msc/ajax-loader.gif' \ No newline at end of file diff --git a/app/views/orders/success.html.haml b/app/views/orders/success.html.haml new file mode 100644 index 0000000..3bdbe24 --- /dev/null +++ b/app/views/orders/success.html.haml @@ -0,0 +1,53 @@ +#order-success + %h2.thank-you Thank You + %h3 Your order was successfully processed. + %p We're redirecting you to the "Order History" page in 5 second(s). + %p If you are having difficulties getting there, #{link_to "please click here", orders_path}. + +/ ADBRITE PURCHASES/SALES TRACKER + + + +/ GOOGLE ANALYTICS PURCHASE TRACKER +:javascript + var _gaq = _gaq || []; + _gaq.push(['_setAccount', 'UA-17750582-2']); + _gaq.push(['_trackPageview']); + _gaq.push(['_addTrans', + '#{@order.id}', + '', + '#{@order.total_price.to_f}', + '', + '#{@order.shipping_price.to_f}', + '', + '', + '' + ]); + _gaq.push(['_addItem', + '#{@order.id}', + '#{@order.buyable_id}', + '#{@order.contents}', + '', + '#{@order.subtotal.to_f}', + '1' + ]); + _gaq.push(['_trackTrans']); //submits transaction to the Analytics servers + + (function() { + var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; + ga.src = 'https://ssl.google-analytics.com/ga.js'; + var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); + })(); + + +:javascript + var n = 5; + setInterval(function () { + if (n > 0) { + n--; + $("#redirect-timer").text(n); + } else { + window.location = "#{orders_url(secure:true)}"; + }; + }, 1000); + diff --git a/app/views/password_resets/edit.html.haml b/app/views/password_resets/edit.html.haml new file mode 100644 index 0000000..5875349 --- /dev/null +++ b/app/views/password_resets/edit.html.haml @@ -0,0 +1,17 @@ +#reset-password-page + %h2.reset-your-password Reset Your Password + = form_for @account, :url => password_reset_path(:code => params[:code]) do |f| + - if @account.errors.any? + #errorExplanation + %p Oops, please correct the following items to proceed: + %ul + - @account.errors.full_messages.each do |msg| + %li= msg + .field + = f.label :password + = f.password_field :password + .field + = f.label :password_confirmation, "Confirm password" + = f.password_field :password_confirmation + .actions + = f.submit "Update Account", :class => "button" \ No newline at end of file diff --git a/app/views/password_resets/new.html.haml b/app/views/password_resets/new.html.haml new file mode 100644 index 0000000..db68835 --- /dev/null +++ b/app/views/password_resets/new.html.haml @@ -0,0 +1,8 @@ +#reset-password-page + %h2.reset-your-password Reset Your Password + %p Please fill out the form below. Instructions to reset your password will be sent to you. + = form_tag password_reset_path do + %p.field + = label_tag :email, "Email Address:" + = text_field_tag :email + = submit_tag "Reset my password", :class => "button" diff --git a/app/views/products/_product.html.haml b/app/views/products/_product.html.haml new file mode 100644 index 0000000..8137fea --- /dev/null +++ b/app/views/products/_product.html.haml @@ -0,0 +1,30 @@ +%td.product-listing[product]{:class => product_counter.next.multiple_of?(4) ? "last" : ""} + .product-container.clearfix + .title + %h3= link_to product.name, product + %p max. discount: #{number_to_currency product.max_discount} + .image + = link_to image_tag(product.main_picture.url :index), product + %table.discount-numbers + %tr.retail-price + %td.action + %td.label Retail Value: + %td.value #{ number_to_currency product.retail_price } + %tr.member-points + %td.action - + %td.label MemberPoints: + %td.value #{ number_to_currency product.display_discount(current_user) } + %tr.member-price + %td.action = + %td.label + %span + You Pay: + %td.value + %span.price (#{display_percentage product} off) #{ number_to_currency product.display_price(current_user) } + .redeem + - if logged_in? + = link_to "Redeem MemberPoints", new_order_path(:buyable => product.id, :kind => :reward), :class => "button" + - else + = link_to "Redeem MemberPoints", new_session_path, :class => "button" +- if product_counter.next.multiple_of?(4) + diff --git a/app/views/products/index.html.haml b/app/views/products/index.html.haml new file mode 100644 index 0000000..eae843d --- /dev/null +++ b/app/views/products/index.html.haml @@ -0,0 +1,16 @@ +- content_for :title, "FirstBargain.com - Member Reward Store" + +#reward-store + %h2.members-shop Members Shop + #store-explanation + - if logged_in? + %p You have #{ current_user.points} in MemberPoints. Redeem now for discounts on popular items. + - else + %p #{link_to "Sign in", new_session_path} to view your MemberPoints balance. Redeem your points for discounts on popular items. + #product-listing + #product-filter + %table#main-products + %tr + = render @products + = fill_grid @products, "product", 4 + = pagination @products \ No newline at end of file diff --git a/app/views/products/show.html.haml b/app/views/products/show.html.haml new file mode 100644 index 0000000..fd5fcdd --- /dev/null +++ b/app/views/products/show.html.haml @@ -0,0 +1,49 @@ +- content_for :title, "FirstBargain.com - #{@product.name}" + +#reward-store.clearfix + #main-store-grid + %h2#product-name= @product.name + #product-description + = simple_format @product.description + #secondary-store-grid.clearfix + .product-images + #viewer= image_tag(@product.main_picture.url(:medium), size: "280x260") + %ul#gallery.clearfix + - @product.pictures.each do |p| + %li[p] + = image_tag(p.data.url(:thumb), size: "70x65") + :javascript + registerRollover("#{dom_id p}","#{p.data.url :medium}"); + .discount-container + %h3 Member's Discount + %table.discount-numbers + %tr.retail-price + %td.action + %td.label Retail Value: + %td.value #{number_to_currency @product.retail_price} + %tr.member-points + %td.action - + %td.label MemberPoints: + %td.value #{number_to_currency @product.display_discount(current_user)} + %tr.member-price + %td.action = + %td.label + %span You Pay: + %td.value + %span.price #{number_to_currency @product.display_price(current_user)} (#{display_percentage @product} off) + %tr.shipping-price + %td{:colspan=>"3"} +#{number_to_currency @product.shipping_price} Shipping & Handling + .redeem= link_to "Redeem MemberPoints", new_order_path(:buyable => @product.id, :kind => :reward), :class => "button" + // SHIPPING INFORMATION + - unless @product.bid_pack? + .shipping-information.clearfix + .title Shipping Information + .delivery-cost Delivery Cost: #{ shipping_price @product } + .return-policy + Return Policy: + - if [12,13,14,15,28,29].include? @product.category_id + Gift cards are not eligible for returns + - else + Return within 14 days for any reason + .questions Any Questions? #{ link_to "Contact Us", contact_path } + diff --git a/app/views/sessions/_form.html.haml b/app/views/sessions/_form.html.haml new file mode 100644 index 0000000..d1a29f5 --- /dev/null +++ b/app/views/sessions/_form.html.haml @@ -0,0 +1,20 @@ += form_for @session, :url => session_path(:secure => true) do |f| + - if @session.errors.any? + #errorExplanation + %p Oops, please correct the following items to proceed: + %ul + - @session.errors.full_messages.each do |msg| + %li= msg + .field.input + = f.label :username + = f.text_field :username + .field.input + = f.label :password + = f.password_field :password + .password-reset + Forgot your password? #{ link_to "Click here", new_password_reset_path } + .field + = f.check_box :remember_me + = f.label :remember_me + .actions + = f.submit "Login", :id => "login-submit", :class => "button" diff --git a/app/views/sessions/new.html.haml b/app/views/sessions/new.html.haml new file mode 100644 index 0000000..e3c5f03 --- /dev/null +++ b/app/views/sessions/new.html.haml @@ -0,0 +1,11 @@ +- content_for :title, "FirstBargain.com - User Sign In" + +#login-page.clearfix + .left-column-2 + %h2.sign-in + Sign In to Your Account + = render 'form' + .right-column-2 + %h2.new-to-website New to FirstBargain.com? + %p(style="line-height:1.3em;") Welcome to FirstBargain.com, a fun and exciting auction website dedicated to bargain seekers. At First Bargain you can win designer handbags, iPads, gift cards, and all sorts of other popular products for incredibly low prices. + %p= link_to "Register For Free", new_account_path, :id => "signup-for-free", :class => "button" diff --git a/app/views/splashes/show.html.haml b/app/views/splashes/show.html.haml new file mode 100644 index 0000000..e32101c --- /dev/null +++ b/app/views/splashes/show.html.haml @@ -0,0 +1,43 @@ +!!! 5 +%html + %head + = stylesheet_link_tag 'viewer' + = javascript_include_tag 'jquery', 'viewer' + /[if IE 8] + :css + #container { + display: table; + } + /[if IE 7] + :css + body { + font-weight: normal; + font-size: 11px; + } + %body + #container.clearfix + %h1 + = link_to image_tag("header/logo.gif"), root_path + #content-wrapper + #content + #home-page + %h2 Innovative Auctions. Coveted Products. Member Rewards. + %p FirstBargain.com is a fun and exciting auction website dedicated to bargain seekers. At FirstBargain you can win Playstations, iPads, gift cards, and all sorts of other popular products for incredibly low prices. + %p= link_to ("» Click Here to Check Out Our Main Site «").html_safe, "http://www.firstbargain.com" + #signin + = form_for @a, :url => splash_path(:secure => false) do |f| + #errorExplanation + - if @a.errors.any? + %p Sorry, a problem occurred while logging you in: + %ul + - @a.errors.full_messages.each do |msg| + %li= msg + .authorized Authorized Users - Sign In: + .field.clearfix + = f.label :login, "Username" + = f.text_field :login + .field.clearfix + = f.label :password + = f.password_field :password + .actions + = f.submit "Login", :class => "button" \ No newline at end of file diff --git a/app/views/staff_mailer/daily_activity_report.html.haml b/app/views/staff_mailer/daily_activity_report.html.haml new file mode 100644 index 0000000..0d17d61 --- /dev/null +++ b/app/views/staff_mailer/daily_activity_report.html.haml @@ -0,0 +1,56 @@ +%table + %caption Daily Report from #{@since.to_s :default} to #{@now.to_s :default} + %tr + %td Bid Revenue (Sum of Bid Pack Purchases) + %tc= number_to_currency @bidpacks.revenue + %tr + %td Auction Revenue (Sum of Final Auction Closing Prices) + %td= number_to_currency @auctions.revenue + %tr + %td Buy Now Revenue (Sum of Exercised Buy Now Prices) + %td= number_to_currency @buynows.revenue + %tr + %td Members Shop Revenue (Sum of Members Shop Purchases) + %td= number_to_currency @rewards.revenue + %tr + %td Auction COGS (Sum of Retail Prices of Ended Auctions) + %td= number_to_currency @auctions.cogs + %tr + %td Buy Now COGS (Sum of Retail Prices of Buy Now Purchases) + %td= number_to_currency @buynows.cogs + %tr + %td Members Shop COGS (Sum of Retail Prices of Members Shop Purchases) + %td= number_to_currency @rewards.cogs + %tr + %td Total # of Signups + %td= @accounts.size + %tr + %td Total # of Bid Pack Purchases + %td= @bidpacks.size + %tr + %td Total # of Items Auctioned Off + %td= @auctions.size + %tr + %td Total # of Buy Nows + %td= @buynows.size + %tr + %td Total # of Members Shop Purchases + %td= @rewards.size + +%table + %caption Affiliate Report + %tr + %th Total # of Registrations + %td + - @a_signups.each_pair do |aff, count| + %p= "#{aff || 'None'}: #{count}" + %tr + %th Total # of Bid Pack Transactions + %td + - @a_bid_count.each_pair do |aff, count| + %p= "#{aff || 'None'}: #{count}" + %tr + %th Total Value of Bid Pack Transactions + %td + - @a_bid_value.each_pair do |aff, money| + %p= "#{aff || 'None'}: #{number_to_currency money}" \ No newline at end of file diff --git a/app/views/staff_mailer/inquiry.text.erb b/app/views/staff_mailer/inquiry.text.erb new file mode 100644 index 0000000..0e999fa --- /dev/null +++ b/app/views/staff_mailer/inquiry.text.erb @@ -0,0 +1,3 @@ +<%= @contact.message %> + +Sent from <%= @contact.email %> \ No newline at end of file diff --git a/app/views/staff_mailer/weekly_activity_report.html.haml b/app/views/staff_mailer/weekly_activity_report.html.haml new file mode 100644 index 0000000..25e9b9c --- /dev/null +++ b/app/views/staff_mailer/weekly_activity_report.html.haml @@ -0,0 +1,18 @@ +%table + %caption Weekly Report from #{@since.to_s :default} to #{@now.to_s :default} + %tr + %td Total # of New Signups + %td= @new_signups + %tr + %td Total # of New Signups that bought at least one bid pack + %td= @new_purchasers + %tr + %td Total # of Returning Users who bought at least one bid pack + %td= @old_purchasers + %tr + %td Total Bid Revenue from New Customers + %td= number_to_currency @new_bid_revenue + %tr + %td Total Bid Revenue from Returning Customers + %td= number_to_currency @old_bid_revenue + \ No newline at end of file diff --git a/app/views/static/about.html.haml b/app/views/static/about.html.haml new file mode 100644 index 0000000..5b0b389 --- /dev/null +++ b/app/views/static/about.html.haml @@ -0,0 +1,11 @@ +- content_for :title, "FirstBargain.com - About Us" + +#flat-page + %h2.about-us About Us + #about-overview + .unit + %h3 Your First Stop to Bargain Shopping + %p Why pay full price when you can spend 90% less? FirstBargain.com has redefined internet shopping to bring you unheard of deals on today's hottest products. Through our fun and exciting auctions, we offer a wide selection of brand new, factory-sealed products including Apple iPads, flat screen TV's, handbags and more! We warmly welcome you to join the thousands of members who choose us as their first stop to bargain shopping. + .unit + %h3 Innovative Live Auctions + %p Our auctions work quite differently from eBay’s. All items start at $0 and each bid raises the price by only a few pennies. When the remaining time on the auction clock is under 30 seconds (or 20 seconds depending on the auction), each bid adds several seconds back onto the timer. The last bidder standing when the timer runs out wins the auction. Bids costs only $0.75 each, and winners walk away with huge bargains! See our #{ link_to "How It Works", tutorial_path } page to learn more. \ No newline at end of file diff --git a/app/views/static/faq.html.haml b/app/views/static/faq.html.haml new file mode 100644 index 0000000..df09a13 --- /dev/null +++ b/app/views/static/faq.html.haml @@ -0,0 +1,45 @@ +- content_for :title, "FirstBargain.com - Frequently Asked Questions" + +#faq-page-index + %h2.faq Frequently Asked Questions + .wrapper + .row.clearfix + .column.new-users + = link_to "New to FirstBargain?", faq_new_user_path, :class => "button" + %ul + %li= link_to "How to Participate", faq_new_user_path + %li= link_to "Verify Email Address", faq_new_user_path + %li= link_to "Purchase Bid Credits", faq_new_user_path + %li= link_to "Read Bidding Tips", faq_new_user_path + %li= link_to "Choose an Auction", faq_new_user_path + .column.auctions + = link_to "Auctions & Bidding", faq_auctions_path, :class => "button" + %ul + %li= link_to "FirstBargain Auctions Explained", faq_auctions_path + %li= link_to "Winning an Auction", faq_auctions_path + %li= link_to "What Happens if I Don't Win?", faq_auctions_path + %li= link_to "What are Beginner Auctions?", faq_auctions_path + %li= link_to "What is the Bid Assistant?", faq_auctions_path + .column.last.account + = link_to "My Account", faq_account_path, :class => "button" + %ul + %li= link_to "Accessing the \"My Account\" Page", faq_account_path + %li= link_to "Change Username or Password", faq_account_path + %li= link_to "Forgot Password?", faq_account_path + %li= link_to "Change Email Address", faq_account_path + %li= link_to "Refer Friends", faq_account_path + %li= link_to "Redeem Coupons", faq_account_path + .row.clearfix + .column.shipping + = link_to "Shipping & Returns", faq_shipping_path, :class => "button" + %ul + %li= link_to "Order Status", faq_shipping_path + %li= link_to "Shipping Costs", faq_shipping_path + %li= link_to "Delivery Times", faq_shipping_path + %li= link_to "Refund & Returns", faq_shipping_path + .column.payment + = link_to "Payment Information", faq_payment_path, :class => "button" + %ul + %li= link_to "Accepted Payment Methods", faq_payment_path + %li= link_to "Is My Credit Card Information Safe?", faq_payment_path + %li= link_to "Your Credit Card Billing Statement", faq_payment_path diff --git a/app/views/static/faq_account.html.haml b/app/views/static/faq_account.html.haml new file mode 100644 index 0000000..cb4a7ed --- /dev/null +++ b/app/views/static/faq_account.html.haml @@ -0,0 +1,22 @@ +- content_for :title, "FirstBargain.com - FAQ: My Account" + +#faq-page-show + %h2 My Account + .block + %h3 Accessing the "My Account" Page + %p You can find the link to your #{ logged_in? ? (link_to "My Account", account_path) : "\"My Account\"" } page on the top-right corner of your browser next to the "Sign In/Logout" button. + .block + %h3 Change Username or Password + %p To change your username or password, first go to the #{ logged_in? ? (link_to "My Account", account_path) : "\"My Account\"" } page. Then, choose the #{ logged_in? ? (link_to "Account Settings", edit_account_path) : "\"Account Settings\"" } tab on the left side. Enter your new username or password in the appropriate fields and click Submit. + .block + %h3 Forgot Password? + %p Click on the "Signin" button on the top-right corner of your browser. On the bottom of the login box that appears you will see a #{ logged_in? ? "\"click here\"" : (link_to "click here", new_password_reset_path)} link next to the words Forgot your Password? Clicking on the link will take you to a page requesting your email address. Once you click the "Reset Password" button, an email will be sent to you with instructions on resetting your password. + .block + %h3 Change Email Address + %p To update your email address, first go to the #{ logged_in? ? (link_to "My Account", account_path) : "\"My Account\"" } page. Then, choose the #{ logged_in? ? (link_to "Account Settings", edit_account_path) : "\"Account Settings\"" } tab on the left side. Enter your new e-mail address in the appropriate field and click Submit. + .block + %h3 Refer Friends + %p Inviting your friends is quick and easy. Just go to the #{ logged_in? ? (link_to "My Account", account_path) : "\"My Account\"" } page and choose the #{ logged_in? ? (link_to "Invitation", invitations_path) : "\"Invitation\"" } tab on the left side. Enter Your Name and the Recipient's email address and click Submit. If you want to invite multiple friends at once, make sure to separate email addresses using commas. + .block + %h3 Redeem Coupons + %p To redeem a coupon code, first go to the #{ logged_in? ? (link_to "My Account", account_path) : "\"My Account\"" } page. Then, choose the #{ logged_in? ? (link_to "Redeem Coupon", new_coupon_path) : "\"Redeem Coupon\"" } tab on the left side. \ No newline at end of file diff --git a/app/views/static/faq_auctions.html.haml b/app/views/static/faq_auctions.html.haml new file mode 100644 index 0000000..6350a75 --- /dev/null +++ b/app/views/static/faq_auctions.html.haml @@ -0,0 +1,23 @@ +- content_for :title, "FirstBargain.com - FAQ: Auctions & Bidding" + +#faq-page-show + %h2 Auctions & Bidding + .block + %h3 FirstBargain Auctions Explained + %p All auctions start with an initial price of $0. Each bid raises the auction price by a fixed increment (1c, 5c, or 15c depending on the auction). Each time you place a bid, one bid credit is deducted from your account. Also, up to 30 seconds is added to the auction timer each time someone bids. This is similar to the “Going once…Going twice…SOLD” approach of traditional auctions, which gives other bidders a chance to make a higher bid if they wish. You win the auction if you are the highest bidder when the timer reaches zero. + .block + %h3 Winning an Auction + %p When you win an auction, your bid button will turn into a blue "Redeem" button. Click the button and simply follow the checkout instructions. If you choose not to redeem right away, you may still do so within 7 days of the auction closing date by going to the #{ logged_in? ? (link_to "My Account", account_path) : "\"My Account\"" } page. + .block + %h3 What Happens if I Don't Win? + %p If you do not win, the bids you have placed on the auction will not be returned to your account; however, we offer the “Buy Now” feature on most auctions! This feature allows you to use the bids you spent on an auction to buy the same item at a discounted price. See example below: + %p Say you placed 40 bids (or $30 worth) on a $50 item, but another bidder wins the auction. Through “Buy Now” you are given the opportunity to purchase the product for its retail value of $50 minus the $30 you spent in bids. Thus, in this example you would be able to buy the item for just $20. + .block + %h3 What are Beginner Auctions? + %p They are auctions reserved only for customers who have not yet won an auction. You will see them marked with an orange border (only visible to users with no wins). + .block + %h3 What is the Bid Assistant? + %a(name="5") + %p The Bid Assistant is an automated bidding tool that allows you to place bids on auctions even when you are away from the computer. Simply activate it with the click of a button and the Bid Assistant will place bids according to your instructions. + %p You can find the Bid Assistant interface located below the Bid History box for each auction. Input the "Start at" price and the "# of Bids" you want to authorize for use. Now, click the "Activate" button and the Bid Assistant will immediately get to work for you! + %p The Bid Assistant places bids on your behalf when the remaining time on the auction clock is between 0 and 20 seconds. You can set a minimum of 3 bids and a maximum of 50 bids. You may deactivate the Bid Assistant at any time. \ No newline at end of file diff --git a/app/views/static/faq_new_user.html.haml b/app/views/static/faq_new_user.html.haml new file mode 100644 index 0000000..f13e7e6 --- /dev/null +++ b/app/views/static/faq_new_user.html.haml @@ -0,0 +1,19 @@ +- content_for :title, "FirstBargain.com - FAQ: Getting Started" + +#faq-page-show + %h2.getting-started Getting Started + .block + %h3 How to Participate + %p Before you can start bidding on our auctions, you must first register an account and purchase bid credits. Bids costs $0.75 each and can be purchased from our #{ logged_in? ? (link_to "Bids Store", bids_path) : "\"Bids Store\"" }. + .block + %h3 Verify Email Address + %p Upon registration of an account with FirstBargain, you will receive an email asking you to verify your email address. This is to ensure you receive all important notification emails from us. If you have any trouble verifying your email address, please #{ link_to "contact us", contact_path }. + .block + %h3 Purchase Bid Credits + %p Bids $0.75 each and are sold in packs of 30, 50, 100, and 200. Once you purchase a bid pack, you will immediately see bids credited to your account. + .block + %h3 Read Bidding Tips + %p We strongly suggest all new customers to read through our #{ link_to "Bidding Tips", tips_path } page. There you will find helpful hints and strategies to assist you in becoming a successful bidder on FirstBargain! + .block + %h3 Choose an Auction + %p All product for auction on our site are brand new, factory-sealed, and 100% authentic. Now, pick the product you want and start bidding. Happy Bidding! \ No newline at end of file diff --git a/app/views/static/faq_payment.html.haml b/app/views/static/faq_payment.html.haml new file mode 100644 index 0000000..336e380 --- /dev/null +++ b/app/views/static/faq_payment.html.haml @@ -0,0 +1,13 @@ +- content_for :title, "FirstBargain.com - FAQ: Payment Information" + +#faq-page-show + %h2 Payment Information + .block + %h3 Accepted Payment Methods + %p We accept Visa, Mastercard, Discover, and PayPal. + .block + %h3 Is My Credit Card Information Safe? + %p We have partnered with CCBill and PayPal to provide an easy and secure payment solution for our customers. For your protection, any information you provide to us is transmitted via VeriSign's secure 256-bit encryption system. Our company does not store any credit card information. + .block + %h3 Your Credit Card Billing Statement + %p If you pay using a credit card, transactions on your billing statement will appear as CCBILL.COM*FIRSTBARGAIN. If you pay via PayPal, transactions on your billing statement will appear as PAYPAL*FRSTBARGAIN. \ No newline at end of file diff --git a/app/views/static/faq_shipping.html.haml b/app/views/static/faq_shipping.html.haml new file mode 100644 index 0000000..6f0d640 --- /dev/null +++ b/app/views/static/faq_shipping.html.haml @@ -0,0 +1,17 @@ +- content_for :title, "FirstBargain.com - FAQ: Shipping & Returns" + +#faq-page-show + %h2 Shipping & Returns + .block + %h3 Order Status + %p To check the status on any order, go to the #{ logged_in? ? (link_to "My Account", account_path) : "\"My Account\"" } page and choose the #{ logged_in? ? (link_to "Order & Account History", orders_path) : "\"Order & Account History\"" } tab on the left side. + .block + %h3 Shipping Costs + %p Shipping & handling costs are clearly displayed for each item beneath the going price of the auction. These rates apply to all residences and businesses within the 48 US contiguous states. We currently do not ship to P.O. Boxes or any locations outside the United States. + .block + %h3 Delivery Times + %p You can expect most items to arrive within 14 days after placing your order. If you have not received an item after this time, please #{ link_to "contact us", contact_path } to ensure successful delivery. + .block + %h3 Refunds & Returns + %p Items can be returned within 14 days for a refund unless otherwise noted. The item must be in its original condition and packaging to qualify for a full refund, exclusive of bids used. For instructions on obtaining a return authorization, see our #{ link_to "Refunds & Returns", returns_path } page. + %p IMPORTANT: Please #{ link_to "contact us", contact_path } first before attempting to return an item or we may be unable to process a refund. \ No newline at end of file diff --git a/app/views/static/guarantee.html.haml b/app/views/static/guarantee.html.haml new file mode 100644 index 0000000..6f93d0f --- /dev/null +++ b/app/views/static/guarantee.html.haml @@ -0,0 +1,14 @@ +- content_for :title, "FirstBargain.com - Our Guarantee Policy" + +#FirstBargain-guarantee-page + %span.right(style="margin-right:-20px;")= image_tag 'how-to-play/apple-ipad.gif' + .unit + %h3 Your Satisfaction Comes First + %p At First Bargain, we believe that there’s nothing better than a happy customer. That is why we make an effort to respond to all member inquiries within 24 hours. We not only want you to have a fun time bidding on our auctions, but also feel completely satisfied with the products you win. We offer a 14 day #{link_to "return policy", returns_path} because we know that everyone changes their mind once in a while! + .unit + %h3 Always New, Always Authentic + %p Our products are sourced directly from the manufacturer or authorized distributor. This means that all items you receive are guaranteed brand new, factory-sealed, and 100% authentic! If you have any product related questions, please feel free to #{ link_to "contact us", contact_path }. + .unit + %h3 Safe and Fair Internet Practices + %p We take internet security very seriously. FirstBargain.com has partnered with Verisign and CCBill to ensure that all customer credit cards and personal information are processed securely. In addition, our auctions are designed in such a way as to provide a fair auction environment for all of our members. First Bargain employees are not allowed to bid on the auctions, and we guarantee that our company does not use any systems to bid up the price of items. + diff --git a/app/views/static/privacy.html.haml b/app/views/static/privacy.html.haml new file mode 100644 index 0000000..dfc7a56 --- /dev/null +++ b/app/views/static/privacy.html.haml @@ -0,0 +1,58 @@ +- content_for :title, "FirstBargain.com - Privacy Policy" + +%h2.privacy-policy Privacy Policy +.unit + %p First Bargain provides this Privacy Policy to inform you of our policies and procedures regarding the collection, use and disclosure of personal information we receive from users of FirstBargain.com. This Privacy Policy applies only to information that you provide to us through this Site. This Privacy Policy may be updated from time to time. We will notify you of any material changes by posting the new Privacy Policy on the Site. You are advised to consult this policy regularly for any changes. Unless otherwise defined in this Privacy Policy, terms used in this Privacy Policy have the same meanings as in our First Bargain Terms of Service. + %p As used in this policy, the terms “using” and “processing” information include using cookies on a computer, subjecting the information to statistical or other analysis and using or handling information in any way, including, but not limited to collecting, storing, evaluating, modifying, deleting, using, combining, disclosing and transferring information within our organization or among our affiliates within the United States or internationally. +.unit + %h3 Information Collection and Use + %p Our primary goals in collecting information are to provide and improve our Site, services, features and content, to administer your Membership (together, the “Service”) and to enable users to enjoy and easily navigate the Site. +.unit + %h3 Personally Identifiable Information. + %p When you register with us through the Site, as a First Bargain Subscriber or when you choose to create your own profile webpage we will ask you for personally identifiable information. This refers to information about you that can be used to contact or identify you (“Personal Information”). Personal Information includes, but is not limited to, your name, username, phone number, credit card or other billing information, email address and home and business postal addresses, and any other information that you decide to add to your profile webpage. We use your Personal Information mainly to provide the Service and administer your inquiries. + %p We also collect the other information that you provide as part of registration and the administration and personalization of the My Account webpage (e.g., without limitation, zip code (on its own) and individual preferences) (“Non-Identifying Information”). + %p We use your Personal Information (in some cases, in conjunction with your Non-Identifying Information) mainly to provide the Service, complete your transactions, and administer your inquiries. + %p We may also collect information regarding your activity on the Site, such as your bidding history, auctions participated in, auctions won/lost, prices paid, bids used and other similar information associated with your username. We use such information solely in accordance with this Privacy Policy + %p Certain Non-Identifying Information would be considered a part of your Personal Information if it were combined with other identifiers (for example, combining your zip code with your street address) in a way that enables you to be identified. But the same pieces of information are considered Non-Identifying Information when they are taken alone or combined only with other non-identifying information (for example, your viewing preferences). We may combine your Personal Information with Non-Identifying Information and aggregate it with information collected from other First Bargain Users (defined below) to attempt to provide you with a better experience, to improve the quality and value of the Service and to analyze and understand how our Site and Service are used. + %p We may also use the combined information without aggregating it to serve you specifically, for instance to deliver a product to you according to your preferences or restrictions.
We also use your Personal Information to contact you with First Bargain newsletters, marketing or promotional materials and other information that may be of interest to you. If you decide at any time that you no longer wish to receive such communications from us, please follow the unsubscribe instructions provided in any of the communications or update your “user preferences” information. (See “Changing or Deleting Information,” below.) + %p Log Data. When you visit the Site, whether as a First Bargain Subscriber or a non-registered user just browsing (any of these, a “First Bargain User”), our servers automatically record information that your browser sends whenever you visit a website (“Log Data”). This Log Data may include information such as your computer’s Internet Protocol (“IP”) address, browser type or the webpage you were visiting before you came to our Site, pages of our Site that you visit, the time spent on those pages, information you search for on our Site, access times and dates, and other statistics. We use this information to monitor and analyze use of the Site and the Service and for the Site’s technical administration, to increase our Site’s functionality and user-friendliness, and to better tailor it to our visitors’ needs. For example, some of this information is collected so that when you visit the Site again, it will recognize you and serve advertisements and other information appropriate to your interests. We also use this information to verify that visitors to the Site meet the criteria required to process their requests. [We do not treat Log Data as Personal Information or use it in association with other Personal Information, though we may aggregate, analyze and evaluate such information for the same purposes as stated above regarding other Non-Identifying Information.] +.unit + %h3 Cookies + %p Like many websites, we use “cookies” to collect information. A cookie is a small data file that we transfer to your computer’s hard disk for record-keeping purposes. We use cookies for two purposes. First, we utilize persistent cookies to save your registration ID for future logins to the Site. Second, we utilize persistent ID cookies to enable certain features of the Site, to better understand how you interact with the Site and to monitor aggregate usage by First Bargain Users and web traffic routing on the Site. Third party advertisers on the Site may also place or read cookies on your browser. You can instruct your browser, by changing its options, to stop accepting cookies or to prompt you before accepting a cookie from the websites you visit. If you do not accept cookies, however, you may not be able to use all portions of the Site or all functionality of the Service. +.unit + %h3 Emailing Via a First Bargain Account + %p As part of the Service, First Bargain Subscribers may choose to communicate with First Bargain Subscribers and non-registered users through use of their accounts. Where First Bargain Subscribers have selected the option of adding one or more email addresses to an online form, the message they create in the corresponding template will be sent from First Bargain to those email addresses on their behalf. These email addresses will be stored in the address book the First Bargain Subscriber creates and will be used only for the purpose of sending the email communication to the addressee. +.unit + %h3 Inviting Friends Via a First Bargain Account + %p As part of the Service, we may allow First Bargain Subscribers to invite friends to participate in First Bargain service. When First Bargain Subscribers have selected the option of adding one or more email addresses to an online form or via an address book import, the resulting invites will be sent to those email addresses on their behalf. These email addresses will be stored in the import friends function that First Bargain creates and will be used only for the purpose of sending the email invite to the addressee(s) selected by the First Bargain Subscribers. +.unit + %h3 Phishing + %p Identity theft and the practice currently known as “phishing” are of great concern to First Bargain. Safeguarding information to help protect you from identity theft is a top priority. We do not and will not, at any time, request your credit card information, your account ID, login password, or national identification numbers in a non-secure or unsolicited e-mail or telephone communication. For more information about phishing, visit the Federal Trade Commission’s website. +.unit + %h3 Information Sharing and Disclosure + %p First Bargain Users. When you register through the Site and submit your Personal Information to create a profile webpage, First Bargain Users will see your “Screen Name” and the month and year you first registered with First Bargain (“Required Subscriber Identifiers”). You can choose what other Personal Information you provide as part of your profile (“Other Subscriber Information”) and in some cases you can choose whether to share that information publicly on the Site by making selections via the “user preferences” section of your profile webpage. Providing Other Subscriber Information is voluntary and should correlate with the degree of interaction you want to have with First Bargain Users. We recommend that you guard your anonymity and sensitive information and that you not use your real name as your “Screen Name,” since that would allow others to identify you. + %p Auction Data and Bidding History. We may share information on your bidding history, auctions participated in, auctions won/lost, prices paid, bids used and other similar information associated with your username, for the purpose of providing First Bargain Users with information designed to help in the formulation of bidding strategies, in accordance with the options selected by you when creating your user account and profile. + %p Aggregate Information and Non-Identifying Information. We may share aggregated information that does not include Personal Information and we may otherwise disclose Non-Identifying Information and Log Data with third parties for industry analysis, demographic profiling and other purposes. Any aggregated information shared in these contexts will not contain your Personal Information. + %p Service Providers. We may employ third party companies and individuals to facilitate our Service, to provide the Service on our behalf, to perform Site-related services (e.g., without limitation, maintenance services, database management, fulfillment, web analytics and improvement of the Site’s features) or to assist us in analyzing how our Site and Service are used. These third parties have access to your Personal Information only to perform these tasks on our behalf and are obligated not to disclose or use it for any other purpose. [We may also provide Personal Information to our business partners or other trusted entities for the purpose of providing you with information on goods or services we believe will be of interest to you. You can, at any time, opt out of receiving such communications.] + %p Compliance with Laws and Law Enforcement. First Bargain cooperates with government and law enforcement officials and private parties to enforce and comply with the law. We will disclose any information about you to government or law enforcement officials or private parties as we, in our sole discretion, believe necessary or appropriate to respond to claims and legal process (including but not limited to subpoenas), to protect the property and rights of First Bargain or a third party, to protect the safety of the public or any person, or to prevent or stop activity we may consider to be, or to pose a risk of being, any illegal, unethical or legally actionable activity. + %p Business Transfers. First Bargain may sell, transfer or otherwise share some or all of its assets, including your Personal Information, in connection with a merger, acquisition, reorganization or sale of assets or in the event of bankruptcy. +.unit + %h3 Changing or Deleting Your Information + %p All Subscribers may review, update, correct or delete the Personal Information in their registration profile by contacting us. If you completely delete all such information, then your account may become deactivated. If you would like us to delete your record in our system, please send a request via our #{ link_to "Contact Form", contact_path }. We will use commercially reasonable efforts to honor your request. We may retain an archived copy of your records as required by law or for legitimate business purposes. +.unit + %h3 Security + %p First Bargain is very concerned with safeguarding your information. We employ administrative, physical and electronic measures designed to protect your information from unauthorized access. + %p We will make any legally required disclosures of any breach of the security, confidentiality, or integrity of your unencrypted electronically stored “personal data” (as defined in applicable state statutes on security breach notification) to you via email or conspicuous posting on this Site in the most expedient time possible and without unreasonable delay, insofar as consistent with (i) the legitimate needs of law enforcement or (ii) any measures necessary to determine the scope of the breach and restore the reasonable integrity of the data system. +.unit + %h3 International Transfer + %p Your information may be transferred to — and maintained on — computers located outside of your state, province, country or other governmental jurisdiction where the privacy laws may not be as protective as those in your jurisdiction. If you are located outside the United States and choose to provide information to us, First Bargain transfers Personal Information to the United States and processes it there. Your consent to this Privacy Policy followed by your submission of such information represents your agreement to that transfer. +.unit + %h3 Links to Other Sites + %p Our Site contains links to other websites. If you choose to visit an advertiser by “clicking on” a banner ad or other type of advertisement, or click on another third party link, you will be directed to that third party’s website. The fact that we link to a website or present a banner ad or other type of advertisement is not an endorsement, authorization or representation of our affiliation with that third party, nor is it an endorsement of their privacy or information security policies or practices. We do not exercise control over third party websites. These other websites may place their own cookies or other files on your computer, collect data or solicit personal information from you. They may also use JavaScript, web beacons (also known as action tags or single-pixel gifs), and other technologies to measure the effectiveness of their ads and to personalize advertising content. Other sites follow different rules regarding the use or disclosure of the personal information you submit to them. We encourage you to read the privacy policies or statements of the other websites you visit. +.unit + %h3 Our Policy Toward Children + %p This Site is not directed to children under 18. We do not knowingly collect personally identifiable information from children under 13. If a parent or guardian becomes aware that his or her child has provided us with Personal Information without their consent, he or she should contact us. If we become aware that a child under 13 has provided us with Personal Information, we will delete such information from our files. +.unit + %h3 Contacting Us + %p If you have any questions about this Privacy Policy, please #{link_to "Contact Us", contact_path}. + diff --git a/app/views/static/returns.html.haml b/app/views/static/returns.html.haml new file mode 100644 index 0000000..e81663a --- /dev/null +++ b/app/views/static/returns.html.haml @@ -0,0 +1,15 @@ +- content_for :title, "FirstBargain.com - Return Policy" + +%h2.return-policy +.unit + %h3 Making a Bid Refund Request + %p You can request a refund only for unused or unexpired Bid Credits, by submitting a request via our #{link_to "Contact Form", contact_path}. + %p FirstBargain.com reserves the right to reduce your MemberPoints by the amount of the bid refund. If you have used your MemberPoints we reserve the right to deny your refund. Free, used, or expired Bid Credits are not eligible for a refund. FirstBargain.com reserves the right to deny refund requests intended to abuse or manipulate this policy. +.unit + %h3 Submitting a Product Return Request + %p Users have 14 days after delivery to return an item won or purchased through Buy Now unless otherwise noted. Items returned must be in good condition and you are responsible for shipping costs. Return and cancellation requests can be submitted through our #{link_to "Contact Form", contact_path}. + %p If, for any reason, you are unable to return the item in good, working condition, FirstBargain.com will retain the right to accept the returned item and reduce the amount of your refund in a proportion equal to the damage on the item (as determined by FirstBargain.com in its sole discretion). In no case will the return of an item entitle you to a refund of the Bid Credits used to win or purchase the item. +.unit + %h3 Billing Inquiries + %p(style="margin-bottom:7px;") For questions regarding credit card billing statements, please contact our billing partner: + %p.ccbill-contact Website: http://support.ccbill.com
Phone: 1-877-374-0182
Email: ccbillsupport@ccbill.com diff --git a/app/views/static/rewards.html.haml b/app/views/static/rewards.html.haml new file mode 100644 index 0000000..9483b9c --- /dev/null +++ b/app/views/static/rewards.html.haml @@ -0,0 +1,24 @@ +- content_for :title, "FirstBargain.com - Member Rewards Program" +#member-rewards-page + .unit.clearfix(style="min-height:300px;height:auto!important;") + %h3 Buy Now + %span.right= image_tag 'how-to-play/buynow.gif' + %p The Buy Now feature gives you the option to purchase an item at a discount equal to the amount you invested in the auction. + %p Say you placed 100 bids (or $75 worth) on an $149.99 Apple iPod Nano, but another member ends up winning the auction. Through Buy Now, you are given the opportunity to purchase the same $149.99 iPod for only $74.99. + %p This is our way of ensuring that our members never pay more than what the item is worth! Buy Now is available anytime during an auction or within 24 hours after its closing. + .unit.clearfix + %h3 MemberPoints + %p For every $1 in bids you purchase from us, we reward you with 1 MemberPoint. These points can be redeemed for discounts on popular items in our Members Shop. Take advantage of this opportunity to ensure none of your money goes to loss, even if you don’t win some auctions. + .how-to-cell.clearfix + %span.left= image_tag 'how-to-play/memberstore-cell.gif' + %dl.explanation + %dt 1. Product Name + %dd Click on the name or image for detailed product information + %dt 2. Regular Price + %dd Retail value of the item. + %dt 3. MemberPoints + %dd Shows how many of your MemberPoints can be applied to the product. + %dt 4. What You Pay + %dd Your discounted price after applying MemberPoints. The total savings is listed as a percentage. + %dt 5. Redeem Points + %dd Click on this button to apply your points and buy the product. diff --git a/app/views/static/rules.html.haml b/app/views/static/rules.html.haml new file mode 100644 index 0000000..2842aad --- /dev/null +++ b/app/views/static/rules.html.haml @@ -0,0 +1,21 @@ +- content_for :title, "FirstBargain.com - Site Rules" + +#flat-page + #site-rules-page + %h2.site-rules Site Rules + .unit + %p We created the following rules to ensure that all members have the opportunity to win and enjoy their experience at FirstBargain: + .unit + %ol + %li Only 1 account is allowed per individual and per household. + %li You may win up to #{Rails.configuration.daily_win_limit} auctions per day. + %li You may win up to #{Rails.configuration.monthly_win_limit} auctions per calendar month. + %li You may win 1 auction of the same product with a retail value of over $200 per calendar month (e.g. you can only win a certain Xbox once every calendar month). + %li Auction wins must be redeemed within 7 days, after which they expire and can no longer be redeemed. + %li "Buy Now" is available for 24 hours after an auction has ended. ** + %li The use of bots to place bids on auctions is strictly prohibited. + %li FirstBargain employees may not participate in any auctions on FirstBargain.com. + .unit + %p Please note: Breaking these rules violates our Terms of Service and will result in the deactivation of all associated customers’ accounts. We cannot honor any items won while in violation of the Terms of Service. Furthermore, refunds will not be processed for any bids used to win auctions while violating the Terms of Service. + .disclaimer ** Buy Now is not available on some auctions. Please check each auction before bidding. + \ No newline at end of file diff --git a/app/views/static/tips.html.haml b/app/views/static/tips.html.haml new file mode 100644 index 0000000..cf49816 --- /dev/null +++ b/app/views/static/tips.html.haml @@ -0,0 +1,23 @@ +- content_for :title, "FirstBargain.com - Bidding Tips" + +#flat-page + #bidding-tips-page + #tips-rules-wrapper + = link_to "Bidding Tips", tips_path, :class => "button", :id => "bidding-tips-link" + = link_to "Site Rules", rules_path, :class => "button", :id => "site-rules-link" + .wrapper + %h2.bidding-tips Bidding Tips + .unit + %p New to First Bargain? Don't know where to start? Below are some tips to help you get started: + .unit + %h3 Observe before bidding. + %p Before you start bidding away, we suggest you watch a few auctions and look through the past auctions to get an idea of how our auctions work. You might notice that some items get more bids than others or that auctions have higher competition during certain times of the day. Use these observations to your advantage by coming up with a strategy to help yourself win with fewer bids! + .unit + %h3 Start small and work your way up. + %p This is a point we always stress to our customers. The common mistake of going straight for a big screen TV or an Apple iPad can be a discouraging experience for many new users. These big ticket items attract a large number of bidders, and novice users may find themselves wasting a bunch of their bids. So start off on the smaller ticket items where you can practice bidding with less competition and then gradually move on to the bigger ticket items as you gain experience. + .unit + %h3 Ready to pay retail. + %p By going into an auction “ready to pay retail”, you’re in a win-win situation. If you were already planning to buy an iPod Touch or a Sony camera, why not try winning it at First Bargain? If you win, you’ll most likely save 60-90% off the retail value. If you’re outbid, no big deal! We offer Buy Now on most of our products, which means you can buy the same product at a discount equal to 100% of the value of bids you used in the auction. But before you go all out bidding, first make sure that Buy Now is offered on the item. Due to inventory restrictions, the Buy Now feature is not offered on some items. For these auctions, we recommend that prior to entering the auction you set a limit on the number of bids you are comfortable using. It’s very easy to get carried away in the heat of bidding, but it never feels good to come out empty-handed after having placed hundreds of bids on an auction. + .unit + %h3 Bid early. + %p Many users like to bid at the very last second of an auction in hopes that they end up the highest bidder, once the timer resets. Although this strategy may work 99% of the time, there are times when your internet connection slows down and your bid does not quite make it to our servers in time. Even with today’s advanced technology, everyone can experience internet lag here and there. As a rule of thumb always bid with at least 5 seconds remaining on the auction clock, so you can stay in the game longer and win! diff --git a/app/views/static/tos.html.haml b/app/views/static/tos.html.haml new file mode 100644 index 0000000..8892e13 --- /dev/null +++ b/app/views/static/tos.html.haml @@ -0,0 +1,87 @@ +.unit + %h2.terms-of-service Terms of Service + %p Welcome to FirstBargain.com. FirstBargain.com and/or its affiliates ("FirstBargain.com", "First Bargain", "we" or "us") provide this website ("Site") and the services available through this Site ("Services") to you subject to the following conditions. If you visit or shop at this Site, you accept these terms and conditions ("Terms"). Please read them carefully. We reserve the right, in our sole discretion, at any time to modify, discontinue or terminate the Site and Services, or modify these Terms without advance notice. No material changes to these Terms will be effective unless we have provided you with notice of such changes. If such changes are not acceptable to you, your sole remedy is to cease using this Site and Services, and if applicable, cancel your Site account. By continuing to access or use this Site and Services after we have notified you of the revised Terms, you agree to be bound by such revised Terms. +.unit + %h3 SITE ACCESS + %p Subject to your compliance with these Terms, FirstBargain.com grants you a limited license to access and make personal use of this Site and not to download or modify it, or any portion of it, except with express written consent of FirstBargain.com. This license does not include any resale or commercial use of this Site or its contents; any collection and use of any product listings, descriptions, or prices; any derivative use of this Site or its contents; any downloading or copying of account information for the benefit of others; or any use of data mining, robots, or similar data gathering and extraction tools. This Site or any portion of this Site may not be reproduced, duplicated, copied, sold, resold, visited, or otherwise exploited except as expressly permitted under these Terms. You may not frame or utilize framing techniques to enclose any trademark, logo, or other proprietary information (including images, text, page layout, or form) of FirstBargain.com without express written consent. You may not use any meta tags or any other "hidden text" utilizing FirstBargain.com's name or trademarks without the express written consent of FirstBargain.com. Any unauthorized use terminates the permission or license granted by FirstBargain.com. You may not use any FirstBargain.com logo or other proprietary graphic or trademark as part of a link to our Site without our express written permission. +.unit + %h3 ELIGIBILITY + %p By registering, you agree that you are a resident of the United States, 18 years of age or older and able to enter into binding contracts. Employees of FirstBargain.com are not eligible to use the site or bid on auctions. +.unit + %h3 YOUR ACCOUNT + %p In order to access certain features of the Site and Services, and to post content as described below, you must create an account with us. You may register only one user account per household. During the registration process, you will be asked to choose a username. FirstBargain.com reserves the right to cancel an account, refuse registration or change a username if it is found to be offensive, illegal, infringing upon the rights of others or if it breaches these terms in any other way. You are responsible for maintaining the confidentiality of your account and password and for restricting access to your computer, and you agree to accept responsibility for all activities that occur under your account or password. FirstBargain.com reserves the right to refuse service, terminate accounts, cancel orders or disqualify you when in FirstBargain.com’s sole opinion you have violated the terms of this agreement. When you register at FirstBargain.com you consent to receive communications from us electronically. We will communicate with you electronically for purposes of advising you on transactions, shipments and customer service. From time to time, we may also communicate with you for marketing purposes. You will be given an opportunity to unsubscribe from such marketing communications at any time. +.unit + %h3 PURCHASING AND PAYING FOR BID CREDITS + %p Bid Credits ("Bid Credits"), are purchased by you prior to bidding. Bid Credits can be purchased in bundles at prices that will be noted on the site. Payment can be made by credit card, debit card or via PayPal. IMPORTANT! BID CREDITS ARE VALID FOR ONE YEAR AFTER THEY HAVE BEEN CREDITED TO YOUR ACCOUNT. UPON EXPIRATION, BID CREDITS BECOME VOID AND CAN NO LONGER BE PLACED. Once a Bid Credit is used, it is deducted from your account and can no longer be used. Refunds will not be issued for used Bid Credits, expired Bid Credits or free Bid Credits. For further information on refunds please see our Refund Policy. +.unit + %h3 MEMBER POINTS + %p At the time of Bid Credit purchase, FirstBargain.com will deliver MemberPoints ("MemberPoints", "MemberPoint", "Member Points", "Member Point") in amount equal to the dollar value of the purchased Bid Credits. MemberPoints can be used in the Members Shop ("Members Shop") to purchase items at a discount level determined solely by FirstBargain.com. MemberPoints are granted for only Bid Credits purchased through our Bid Pack Store, and expire after 365 days from the date of purchase. Bid Credits won from auctions or from auction "Buy Now" are not eligible for MemberPoints. + %p MemberPoints are not redeemable for cash and have no cash value. If your account is closed or the Members Shop is cancelled, for any reason, all MemberPoints not yet redeemed are forfeited. MemberPoints forfeited as a result of account or Members Shop closure or violation of these Terms are the sole property of FirstBargain.com. +.unit + %h3 HOW FirstBargain.com WORKS + %p With each Bid Credit placed the price of the item on which you are bidding increases by the amount specified. Each new Bid Credit adds time to the auction in an amount equal to the displayed time increment. The auction ends when the auction clock reaches zero. The final bidder is declared the winner. Disputes over auction winners will be decided based on the records maintained by FirstBargain.com. Decisions made by FirstBargain.com in these instances shall be final and binding. Auctions may offer the "Buy Now" option. "Buy Now" will allow you to buy the item bid upon for a price equal to the FirstBargain.com retail value less the value of any Bid Credits used by you during the auction. The option to "Buy Now" will be offered for a limited period of time (usually 24 hours after the auction ends) after which the option to "Buy Now" is revoked. +.unit + %h3 WINNING THE AUCTION/PAYMENT FOR "BUY NOW" + %p After an auction has ended, the successful bidder will be presented with a website page that will allow for the auction win to be confirmed, and payment and shipping information to be entered. Auction winners will have 7 days to submit the information on this page and make the payment due. After this 7 day period has elapsed, the ability to claim the item won at auction will be revoked. Similarly, users who choose to "Buy Now" will be presented with a website page that will allow the user to confirm the desire to "Buy Now", enter payment and shipping information and checkout. Users have up to 24 hours after the close of an auction to use the "Buy Now" feature. You may win up to #{Rails.configuration.monthly_win_limit} auctions in a calendar month or #{Rails.configuration.daily_win_limit} times a day, whichever is fewer. Only 1 win of the same product with a retail value over $200 is allowed per calendar month. +.unit + %h3 MEMBERS SHOP + %p From time to time, FirstBargain.com may offer items for sale in the Members Shop ("Members Shop, Member Shop"). Usage of the Member Shop is limited to FirstBargain.com users that have purchased Bid Credits and have been awarded Member Points. Users using the Member Shop will be given the opportunity to buy items at a discount using their Member Points. Purchases made in the Member Shop will be completed in an identical manner to those made via the "Buy Now" feature. +.unit + %h3 RETURNS + %p You have the right to return items purchased following a winning auction or "Buy Now" purchase. Users have 14 days after delivery to return an item. You are responsible for shipping costs on returned items and items returned must be in good condition. Requests for returns or cancellations must be made in writing via our #{ link_to "Contact Us", contact_path } form: + %p If, for any reason, you are unable to return the item in good, working condition, FirstBargain.com will retain the right to accept the returned item and reduce the amount of your refund in a proportion equal to the damage on the item (as determined by FirstBargain.com in its sole discretion). In no case will the return of an item entitle you to a refund of the Bid Credits used to win or purchase the item. + %p(style="margin-bottom:7px;") For questions regarding credit card billing statements, please contact our billing partner: + %p.ccbill-contact Website: http://support.ccbill.com
Phone: 1-877-374-0182
Email: #{mail_to "ccbillsupport@ccbill.com?subject=Billing%20Inquiry%20for%20FirstBargain.com", "ccbillsupport@ccbill.com"} +.unit + %h3 SHIPPING + %p Shipping costs will be clearly displayed for each item. Delivery will be made from our suppliers or from our warehouse to the address supplied by the user. Unless otherwise stated, delivery is available within the 48 contiguous United States. Stated delivery times should be considered to be guidelines and are not delivery guarantees. FirstBargain.com shall be entitled to involve third parties to satisfy its contractual obligations without being required to notify the buyer. You are responsible for inspecting the item and reporting any damage to the item to FirstBargain.com promptly upon taking delivery. The successful bidder or user choosing the "Buy Now" option will be responsible for the full shipping costs as displayed. +.unit + %h3 DATA/BIDDING STRATEGIES PROVIDED BY FirstBargain.com + %p From time to time, FirstBargain.com may make available to you certain data related to auctions and users bidding on auctions including but not limited to bidder name, number of Bid Credits, number of auctions bid upon, number of auctions won, item auction history, item pricing, and the like. This data is provided to you by FirstBargain.com in an effort to assist you in implementing bidding strategies. FirstBargain.com makes no warranty for the accuracy or efficacy of this data in formulating winning bidding strategies and use of such data in formulating such strategies is undertaken solely at your risk. In a similar fashion, FirstBargain.com may provide tips and hints related to bidding strategies. These tips, hints and bidding strategies are provided to you by FirstBargain.com in an effort to assist you in implementing bidding strategies. FirstBargain.com makes no warranty for the accuracy or efficacy of these strategies in formulating winning bidding strategies and use of such information in formulating such strategies is undertaken solely at your own risk. +.unit + %h3 COLLUSION/TEAM PLAY + %p Any kind of collusion or team play is strictly forbidden on FirstBargain. By definition, this includes, but is not limited to, two or more members working together as a team, or creating the impression that there are more people involved and competing to win an auction than there actually are, or placing bids until "Buy Now" offers are earned and then switching over to another account to continue to earn further "Buy Now" offers on the same deal. FirstBargain does not allow two members that know each other to participate in the same auction. Two members participating in the auction are by definition engaging in team play, and automatically lose their right to purchase the product or receive any of their spent Credits back. FirstBargain reserves the right to disqualify in its absolute discretion any users they suspect to be working in a team by voiding all their wins and freezing their accounts. No funds, Credits or bids will be returned or transferred into other accounts. +.unit + %h3 SYSTEM OUTAGES + %p At present, and with current technology it is not possible to operate with 100% guaranteed uptime. In some cases, system outages may interrupt the ability to view or bid upon auctions. In this case, FirstBargain.com will halt all auctions and bidding on those auctions until the system outage is resolved. Auctions that are halted will be clearly designated as such. FirstBargain.com will make commercially reasonable efforts to resume the auctions after the outage is resolved. In the event of a system wide outage that prevents you from bidding, FirstBargain.com will refund Bid Credits used in auctions that you were participating in at the time of the auction. +.unit + %h3 CONTENT POLICY + %p Visitors may post reviews, comments, photos, and other content; and submit suggestions, ideas, comments, questions, or other information, so long as the content is not illegal, obscene, threatening, defamatory, invasive of privacy, infringing of intellectual property rights, or otherwise injurious to third parties or objectionable and does not consist of or contain software viruses, political campaigning, commercial solicitation, chain letters, mass mailings, or any form of "spam." You may not use a false e-mail address, impersonate any person or entity, or otherwise mislead as to the origin of content. If you do post content or submit material, and unless we indicate otherwise, you grant FirstBargain.com a nonexclusive, royalty-free, perpetual, irrevocable, and fully sublicensable right to use, reproduce, modify, adapt, publish, translate, create derivative works from, distribute, and display such content throughout the world in any media. You grant FirstBargain.com and sublicensees the right to use the name that you submit in connection with such content, if they choose. You represent and warrant that they own or otherwise have the rights to post the content; that the content is accurate; that use of the content supplied does not violate this policy and will not cause injury to any person or entity; and that you will indemnify FirstBargain.com for all claims resulting from content supplied. FirstBargain.com has the right but not the obligation to monitor and edit or remove any activity or content at its sole discretion, and may do so at any time without notice. FirstBargain.com does not endorse any user content or any opinion, recommendation or advice expressed therein, and expressly disclaims any and all liability for any content posted by a user or any third party. Furthermore, FirstBargain.com may immediately terminate your account and access to the Site if you post infringing content. +.unit + %h3 THIRD PARTY WEBSITES + %p Our Site may contain links to other websites operated by third parties, and these sites may likewise contain links to other websites. We assume no liability for the content of external links. The operators of the sites linked to and from the Site are solely responsible for their contents. You should carefully review the terms and conditions of such sites, including their privacy policies, before visiting them. +.unit + %h3 WHAT YOU MUST NOT DO + %p The Site and Services may be used and accessed for lawful purposes only. You agree to be bound by all applicable local, state, national and foreign laws, treatises and regulations in connection with your use of the Site and Services. In addition, without limitation, you agree that you will not do any of the following while using or accessing the Site or Services: (a) Circumvent, disable or otherwise interfere with security related features of the Site or features that prevent or restrict use or copying of any content; (b) Upload, stream, email or otherwise transmit any content in violation of these Terms; (c) Use any meta tags or other hidden text or metadata utilizing name, trademark, URL or product name incorporating "FirstBargain.com"; (d) Upload, stream, email or otherwise transmit any unsolicited or unauthorized advertising, promotional materials, junk mail, spam, chain letters, "pyramid schemes" or any other form of solicitation, as well as viruses or other computer code that may interrupt, destroy, limit the functionality of the Site or the Services, or interfere with the access of any user to the Site or the Services; (e) Forge any TCP/IP packet header or any part of the header information in any posting or in any way use the Site or Services to send altered, deceptive or false source-identifying information; (f) Attempt to probe, scan or test the vulnerability of any system or network or breach or impair or circumvent any security or authentication measures protecting the Site or Services; (g) Attempt to decipher, decompile, disassemble or reverse engineer any of the software used to provide the Site or Services, (h) Collect or store personal data about other users without their express permission; (j) Impersonate or misrepresent your affiliation with any person or entity, through pretexting or some other form of social engineering or otherwise commit fraud or (k) Encourage or instruct any other individual to do any of the foregoing or to violate any term of these Terms. (l) Use any third party bidding software or other "bot" to assist in bidding or harvesting site data. +.unit + %h3 LIMITATION OF LIABILITY + %p IN NO EVENT WILL FIRSTBARGAIN.COM BE LIABLE TO YOU OR ANY THIRD PARTY FOR ANY CONSEQUENTIAL, EXEMPLARY, INCIDENTAL, SPECIAL, OR PUNITIVE DAMAGES, INCLUDING BUT NOT LIMITED TO LOST PROFIT DAMAGES ARISING FROM YOUR USE OF THE SERVICES, EVEN IF FIRSTBARGAIN.COM HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. NOTWITHSTANDING ANYTHING TO THE CONTRARY CONTAINED HEREIN, FIRSTBARGAIN.COM'S LIABILITY TO YOU FOR ANY CAUSE WHATSOEVER AND REGARDLESS OF THE FORM OF THE ACTION, WILL AT ALL TIMES BE LIMITED TO THE AMOUNT PAID BY YOU TO FIRSTBARGAIN.COM FOR BID CREDITS IN THE 12-MONTH PERIOD PRECEDING THE EVENT THAT GAVE RISE TO THE LIABILITY. +.unit + %h3 DISCLAIMER OF WARRANTIES + %p THE ITEMS THAT YOU MAY WIN ON THE SITE ARE SOLD WITH THE MANUFACTURE’S LIMITED WARRANTY ONLY. YOU ACKNOWLEDGE AND AGREE THAT THE WARRANTY PERIOD VARIES BY MANUFACTURER AND PRODUCT. NO WARRANTY APPLIES TO USED ITEMS. IF FOR ANY REASON YOU ARE NOT SATISFIED WITH ANY ITEMS PURCHASED THROUGH THE SITE OR WISH TO RECEIVE SUPPORT, YOU MUST CONTACT THE MANUFACTURER. EXCEPT AS OTHERWISE EXPRESSLY SET FORTH HEREIN, THE SITE, THE SERVICES AND THE PRODUCTS AVAILABLE ON THE SITE ARE PROVIDED ON AN "AS IS" AND "AS AVAILABLE" BASIS WITHOUT WARRANTIES OF ANY KIND AND FIRSTBARGAIN.COM EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND, EXPRESS, IMPLIED OR STATUTORY, RELATING THERETO, INCLUDING WITHOUT LIMITATION THE WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, COURSE OF DEALING OR COURSE OF PERFORMANCE. FURTHERMORE, FIRSTBARGAIN.COM DISCLAIMS ANY WARRANTIES: (I) REGARDING THE SECURITY, ACCURACY, RELIABILITY, TIMELINESS AND PERFORMANCE OF THE SITE AND THE SERVICES; AND (II) THAT THE SITE AND THE SERVICES WILL BE ERROR-FREE OR THAT ANY ERRORS WILL BE CORRECTED. NO ADVICE OR INFORMATION, WHETHER ORAL OR WRITTEN, OBTAINED BY YOU FROM FIRSTBARGAIN.COM, INCLUDING WITHOUT LIMITATION ANY DATA OR BIDDING STRATEGIES PROVIDED UNDER THESE TERMS, WILL CREATE ANY WARRANTY NOT EXPRESSLY STATED IN THESE TERMS. FURTHERMORE, YOU UNDERSTAND AND AGREE THAT THERE IS NO GUARANTEE THAT YOU WILL BE ABLE TO WIN ITEMS ON WHICH YOU HAVE BID, AND THAT EVERY TIME YOU PLACE A BID FOR AN ITEM, SUCH BID IS DEDUCTED FROM YOUR USER ACCOUNT AND CAN NO LONGER BE USED, WHETHER OR NOT YOU WILL BE ABLE TO WIN THE ITEM. +.unit + %h3 INDEMNIFICATION + %p You agree to defend, indemnify, and hold FirstBargain.com, its officers, directors, employees and agents, harmless from and against any claims, liabilities, damages, losses, and expenses, including without limitation reasonable attorney’s fees and costs, arising out of or in any way connected with (i) your access to or use of the Site and/or the Services; (ii) your violation of these Terms; (iii) your violation of any third party right, including without limitation any intellectual property right, publicity, confidentiality, property or privacy right; or (iv) any claim that any of your content caused damage to a third party. +.unit + %h3 IP OWNERSHIP + %p FirstBargain.com owns and retains all proprietary rights in the Site (other than with respect to content posted by you under these Terms) and the Services. The Site contains the copyrighted material, trademarks, and other proprietary information of FirstBargain.com and its licensors, and is protected to the maximum extent permitted by US and foreign laws and international treaty provisions. Access and use of the Site and the Services does not grant you any right or license to the copyrighted material, trademarks, tradenames, logos, images, or other proprietary information of FirstBargain.com and its licensors. +.unit + %h3 MISCELLANEOUS + %p These Terms constitute the entire agreement between the parties with respect to the use of the Site and the Services and supersedes all previous and contemporaneous agreements, proposals and communications, written or oral between the parties. Any waiver by either party of any violation of any provision of these Terms will not be deemed to waive any further or future violation of the same or any other provision. If any part or provision of these Terms is held to be unenforceable for any purpose, including but not limited to public policy grounds, then the remainder of these Terms will be fully enforceable as if the unenforceable part or provision never existed. There are no third party beneficiaries of any promises, obligations or representations made by FirstBargain.com. You may not assign their rights and delegate their duties under these Terms to any third parties. THESE TERMS AND ANY DISPUTE RELATING TO THESE TERMS WILL BE GOVERNED BY THE LAWS OF THE UNITED STATES AND THE LAWS OF THE STATE OF WASHINGTON, WITHOUT REGARD TO U.S. OR WASHINGTON CHOICE OF LAW RULES. YOU AND FIRSTBARGAIN.COM AGREE AND CONSENT THAT JURISDICTION, PROPER VENUE, AND THE MOST CONVENIENT FORUMS FOR ALL CLAIMS, ACTIONS, AND PROCEEDINGS OF ANY KIND RELATING TO FIRSTBARGAIN.COM OR THE MATTERS IN THESE TERMS WILL BE EXCLUSIVELY IN COURTS LOCATED IN SEATTLE, WASHINGTON. +.unit + %h3 COMPANY INFORMATION + %p(style="margin-left:15px;") + Expedient Shopping, Limited
+ Minshull House
+ 67 Wellington Road North
+ Stockport, Cheshire, SK4 2LP
+ United Kingdom
+ %p(style="margin-left:15px;") + Managed by:
+ Expedient Shopping, Inc
+ 2018 156th Avenue Northeast
+ Bellevue, WA 98007
+ United States of America +.unit + %h3 REFUND POLICY + %p Please refer to our #{link_to "Refunds & Returns Policy", returns_path}. \ No newline at end of file diff --git a/app/views/static/tutorial.html.haml b/app/views/static/tutorial.html.haml new file mode 100644 index 0000000..24d9997 --- /dev/null +++ b/app/views/static/tutorial.html.haml @@ -0,0 +1,58 @@ +- content_for :title, "FirstBargain.com - How It Works" + +#how-to-play-page + .unit#how-to-overview.clearfix + %ul + %li Buy bid credits to participate (you use 1 bid credit each time you bid) + %li All auctions start at $0 + %li Each bid raises the price by a few cents & adds up to 30 seconds to the clock + %ul + %li Last bidder standing when timer expires, wins! + %li Winner pays final auction price and saves up to 90% off retail + %ul.last + %li If you're outbid, apply the value of your used bids toward a discount on the same item at its retail value + %li Redeem your MemberPoints for discounts on popular items in the #{ link_to "Members Shop", products_path }. + .unit#get-started-now.clearfix + - unless current_user + .right= link_to "Register for Free", new_account_path, :id => "signup-for-free", :class => "button" + #sign-up + %h3 Registration is FREE and EASY! + - else + .right= link_to "Register for Free", bids_path, :id => "buy-bid-credits", :class => "button" + #buy-bids + %h3 Buy bid credits to get started. + %p You need them to participate. They cost $0.75 each. + %h2.faq Frequently Asked Questions + .unit + %h3 How do I get started? + %ol + - unless logged_in? + %li #{ link_to "Sign up", new_account_path } to become a member. Registration is free and easy. + %li Buy bid credits. They cost only $0.75 each and are sold in packages of varying size. + - else + %li #{ link_to "Buy bid credits", bids_path }. They cost only $0.75 each and are sold in packages of varying size. + %li Pick an auction and start bidding! We offer products ranging from gift cards to high-end designer handbags. + .unit + %h3 How do auctions work? + %p All auctions start at $0 and depending on the auction, each bid raises the price by 1¢, 5¢, or 15¢. If the remaining time on the auction clock is under 30 seconds (or 20 seconds depending on the auction), each bid will reset the timer back to 30 seconds (or 20 seconds) to give everyone an equal chance to participate. This timer reset amount is clearly displayed on each auction. There is no limit for how many bids you can place on an item. So if someone outbids you while the auction is still live, you can bid again to reclaim the highest bidder spot. You win the auction if you are the last bidder standing when the timer expires. + .unit + %h3 What do I pay? + %p To participate in our auctions, you need bid credits. They cost $0.75 each.
When you win something, you pay the final auction price plus shipping and handling.
If you bid on an auction but don’t win, you can “Buy Now” the same item for the retail value minus the cost of bids you used in the auction.
Please note: spent bids are not refundable & the minimum charge on any transaction is $2.95. See our #{ link_to "Member Rewards", rewards_path } page to learn more. + .unit + %h3 How many times can I win? + %p At First Bargain, you can win up to #{Rails.configuration.monthly_win_limit} times a month, #{Rails.configuration.daily_win_limit} times a day. You may win 1 auction of the same product with a retail value of over $200 per calendar month (e.g. you can only win a certain Xbox once every calendar month). This gives everyone a fair chance to win great deals. + .unit + %h3 How do I get discounts in the Members Shop? + %p For every $1 in bid credits you purchase from us, we credit your account with 1 MemberPoint. You can redeem these points to get discounts on gift cards and other popular items we offer in the #{ link_to "Members Shop", products_path }. + .unit + %h3 Are all products new? + %p Absolutely! We get our products directly from manufacturers and authorized distributors. We guarantee that every item offered on our site is brand new, factory-sealed, and 100% authentic. + .unit + %h3 How long does shipping take? + %p Most items will arrive within 14 days after making payment. You can track the status of your item in the #{current_user ? link_to("My Account", orders_path) : "My Account"} page. If you have not received your item after 14 days, please notify us right away so we can ensure that your order is on the way. + .unit + %h3 Where does First Bargain ship? + %p We currently ship to all states in the U.S. except for Alaska and Hawaii. + .unit + %h3 What’s the return policy? + %p Items can be returned within 14 days for a refund unless otherwise noted. The item must be in its original condition and packaging to qualify for a full refund, exclusive of bids used. We will also refund you for any unused bid credits. For detailed information, see our #{ link_to "Refunds & Returns", returns_path } page. \ No newline at end of file diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..9f1b1b7 --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +# This file is used by Rack-based servers to start the application. + +require ::File.expand_path('../config/environment', __FILE__) +run FirstBargain::Application diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..7a2d03e --- /dev/null +++ b/config/application.rb @@ -0,0 +1,67 @@ +require File.expand_path('../boot', __FILE__) + +require 'rails/all' + +# If you have a Gemfile, require the gems listed there, including any gems +# you've limited to :test, :development, or :production. +Bundler.require(:default, Rails.env) if defined?(Bundler) + +module FirstBargain + class Application < Rails::Application + # Settings in config/environments/* take precedence over those specified here. + # Application configuration should go into files in config/initializers + # -- all .rb files in that directory are automatically loaded. + + # Custom directories with classes and modules you want to be autoloadable. + config.autoload_paths += %W(#{config.root}/lib) + + # Only load the plugins named here, in the order given (default is alphabetical). + # :all can be used as a placeholder for all plugins not explicitly named + # config.plugins = [ :exception_notification, :ssl_requirement, :all ] + + # Activate observers that should always be running + #config.active_record.observers = :bid_observer, :order_observer + + # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. + # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. + config.time_zone = 'Pacific Time (US & Canada)' + + # Configure the default encoding used in templates for Ruby 1.9. + config.encoding = "utf-8" + + config.action_view.javascript_expansions[:cdn] = %w[ + //ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js + //ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js + ] + + # Configure sensitive parameters which will be filtered from the log file. + config.filter_parameters += [:password] + + config.cache_store = :redis_store, {db: 1} + + # Override me in production.rb + config.cdn_enabled = false + + config.active_record.include_root_in_json = false + + config.buy_now_expiration = 1.day + config.won_auction_expiration = 1.week + config.referral_bonus = 20 + config.subscription_bonus = 0 + config.monthly_win_limit = 10 + config.daily_win_limit = 3 + config.price_threshold = Money.new(20000) # one $200 item per month + config.admins = [1,2,3] + config.bid_unit_price = Money.new(75) + config.banned_domains = /mailinator|trashymail|mailexpire|maileater|jetable|spambox|spamhole|pookmail/i + + config.recaptcha_public = ENV["RECAPTCHA_PUBLIC"] + config.recaptcha_private = ENV["RECAPTCHA_PRIVATE"] + + Time::DATE_FORMATS[:default] = "%m/%d/%y - %I:%M%p" + Time::DATE_FORMATS[:order_history] = "%m-%d-%Y%I:%M %p %Z" + Time::DATE_FORMATS[:admin] = "%m/%d/%y - %I:%M:%S%p" + Time::DATE_FORMATS[:auction] = "%m/%d %I:%M %p %Z" + Time::DATE_FORMATS[:bid] = "%r" + end +end diff --git a/config/assets.yml b/config/assets.yml new file mode 100644 index 0000000..75923e1 --- /dev/null +++ b/config/assets.yml @@ -0,0 +1,38 @@ +javascripts: + base: + - public/javascripts/sprintf.js + - public/javascripts/tiptip.js + - public/javascripts/rails.js + - public/javascripts/application.js + - public/javascripts/poller.js + slideshow: + - public/javascripts/slideshow.js + widget: + - public/javascripts/widget.js +stylesheets: + base: + - public/stylesheets/base.css + - public/stylesheets/dashboard.css + - public/stylesheets/flat.css + - public/stylesheets/messages.css + - public/stylesheets/orders.css + - public/stylesheets/product.css + - public/stylesheets/tiptip.css + - public/stylesheets/jqueryui.css + admin: + - public/stylesheets/base.css + - public/stylesheets/messages.css + - public/stylesheets/admin.css + - public/stylesheets/jqueryui.css + viewer: + - public/stylesheets/viewer.css + ie: + - public/stylesheets/ie.css + ie_seven: + - public/stylesheets/ie7.css + widget_default: + - public/stylesheets/external/widget-default.css + appconsumer: + - public/stylesheets/external/appconsumer.css + dailymakeover: + - public/stylesheets/external/dailymakeover.css \ No newline at end of file diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..ab6cb37 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,13 @@ +require 'rubygems' + +# Set up gems listed in the Gemfile. +gemfile = File.expand_path('../../Gemfile', __FILE__) +begin + ENV['BUNDLE_GEMFILE'] = gemfile + require 'bundler' + Bundler.setup +rescue Bundler::GemNotFound => e + STDERR.puts e.message + STDERR.puts "Try running `bundle install`." + exit! +end if File.exist?(gemfile) diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..ec7441a --- /dev/null +++ b/config/database.yml @@ -0,0 +1,18 @@ +# SQLite version 3.x +# gem install sqlite3-ruby (not necessary on OS X Leopard) +development: + adapter: sqlite3 + database: db/development.sqlite3 + pool: 5 + timeout: 5000 + +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". +# Do not set this db to the same as development or production. +test: + adapter: sqlite3 + database: db/test.sqlite3 + pool: 5 + timeout: 5000 + +# Add your production and staging environments below... \ No newline at end of file diff --git a/config/deploy.rb b/config/deploy.rb new file mode 100644 index 0000000..d6b4063 --- /dev/null +++ b/config/deploy.rb @@ -0,0 +1,103 @@ +$:.unshift(File.expand_path('./lib', ENV['rvm_path'])) # Add RVM's lib directory to the load path. +require "rvm/capistrano" + +require 'bundler/capistrano' + +#require 'config/boot' +#require 'hoptoad_notifier/capistrano' + +set :application, "First Bargain" +set :scm, :git +set :repository, "git@github.com:expedientshopping/firstbargain.git" +set :branch, CLI.ui.ask("What branch? ") +set :user, "deploy" +set :deploy_via, :remote_cache +set :scm_auth_cache, true +set :use_sudo, false +ssh_options[:forward_agent] = true +set :rvm_ruby_string, '1.9.2' +set :rvm_type, :user + +desc "Run tasks on staging" +task :staging do + server "SECRET.blueboxgrid.com", :web, :app, :db, :primary => true + set :rails_env, 'staging' + set :deploy_to, "/home/deploy/staging" + set :password, "SECRET" +end + +desc "Run tasks in production environment" +task :production do + set :rails_env, 'production' + server "SECRET2.blueboxgrid.com", :web, :app, :db, :primary => true + set :deploy_to, "/home/deploy/firstbargain" + after "deploy", "deploy:push_deploy_tag" + after "deploy:symlink", "deploy:update_crontab" +end + +namespace :deploy do + before "deploy:update", "disable_web" + after "deploy:update", "deploy:migrate" + after "deploy:restart", "deploy:web:enable" + after "deploy:update", "deploy:cleanup" + after "deploy:symlink", "deploy:jammit" + after "deploy:stop", "daemons:stop" + after "deploy:start", "daemons:start" + after "deploy:restart", "daemons:restart" + + task :start do ; end + task :stop do ; end + task :restart, :roles => :app, :except => { :no_release => true } do + run "#{try_sudo} touch #{File.join(current_path,'tmp','restart.txt')}" + end + + desc "Run Jammit" + task :jammit do + run "cd #{deploy_to}/current && jammit" + end + + desc "Set Git tags" + task :push_deploy_tag do + user = `git config --get user.name`.chomp + email = `git config --get user.email`.chomp + puts `git tag #{rails_env}_#{release_name} #{current_revision} -m "Deployed by #{user} <#{email}>"` + puts `git push --tags origin` + end + + desc "Update the crontab file" + task :update_crontab, :roles => :db do + run "cd #{release_path} && whenever --update-crontab firstbargain" + end +end + +namespace :daemons do + def rails_env + fetch(:rails_env, false) ? "RAILS_ENV=#{fetch(:rails_env)}" : '' + end + + desc "Start Stalker workers and Heartbeat" + task :start, :roles => :app do + run "cd #{current_path};#{rails_env} lib/stalker_worker.rb start" + run "cd #{current_path};#{rails_env} lib/heartbeat.rb start" + end + + desc "Stop Stalker workers and Heartbeat" + task :stop, :roles => :app do + run "cd #{current_path};#{rails_env} lib/stalker_worker.rb stop" + run "cd #{current_path};#{rails_env} lib/heartbeat.rb stop" + end + + desc "Restart Stalker workers and Heartbeat" + task :restart, :roles => :app do + run "cd #{current_path};#{rails_env} lib/stalker_worker.rb restart" + run "cd #{current_path};#{rails_env} lib/heartbeat.rb restart" + end +end + +desc "Put up the maintenance page" +task :disable_web, :roles => :web do + require 'haml' + template = File.read 'app/views/layouts/maintenance.html.haml' + page = Haml::Engine.new(template).render + put page, "#{shared_path}/system/maintenance.html", :mode => 0644 +end diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..61ae066 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,5 @@ +# Load the rails application +require File.expand_path('../application', __FILE__) + +# Initialize the rails application +FirstBargain::Application.initialize! \ No newline at end of file diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..42fd215 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,32 @@ +FirstBargain::Application.configure do + # Settings specified here will take precedence over those in config/environment.rb + + # In the development environment your application's code is reloaded on + # every request. This slows down response time but is perfect for development + # since you don't have to restart the webserver when you make code changes. + config.cache_classes = false + + # Log error messages when you accidentally call methods on nil. + config.whiny_nils = true + + # Show full error reports and disable caching + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + + # Don't care if the mailer can't send + config.action_mailer.raise_delivery_errors = false + + config.action_mailer.delivery_method = :test + + config.active_support.deprecation = :stderr + + config.action_mailer.default_url_options = {host: "firstbargain.dev"} + + # Only use best-standards-support built into browsers + config.action_dispatch.best_standards_support = :builtin + + SslRequirement.disable_ssl_check = true + + config.paypal = ActiveMerchant::Billing::PaypalExpressGateway.new(test: true, login: "expedi_1278081544_biz_api1.gmail.com", password: "1278081548", signature: "A0ZeH-pLSu6Oi15OEJkSBy5Gi2NuAbNHcC3bPb4HvOBTSQa3JH2mzsvQ") + +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..bcb8ab2 --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,39 @@ +FirstBargain::Application.configure do + # Settings specified here will take precedence over those in config/environment.rb + + # The test environment is used exclusively to run your application's + # test suite. You never need to work with it otherwise. Remember that + # your test database is "scratch space" for the test suite and is wiped + # and recreated between test runs. Don't rely on the data there! + config.cache_classes = true + + # Log error messages when you accidentally call methods on nil. + config.whiny_nils = true + + # Show full error reports and disable caching + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + + # Disable request forgery protection in test environment + config.action_controller.allow_forgery_protection = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + #config.cache_store = :memory_store + + #config.monthly_win_limit = 3 + + config.action_mailer.default_url_options = {host: "www.firstbargain.com"} + + SslRequirement.disable_ssl_check = true + + # Use SQL instead of Active Record's schema dumper when creating the test database. + # This is necessary if your schema can't be completely dumped by the schema dumper, + # like if you have constraints or database-specific column types + # config.active_record.schema_format = :sql + + config.active_support.deprecation = :stderr +end diff --git a/config/initializers/backtrace_silencers.rb b/config/initializers/backtrace_silencers.rb new file mode 100644 index 0000000..59385cd --- /dev/null +++ b/config/initializers/backtrace_silencers.rb @@ -0,0 +1,7 @@ +# Be sure to restart your server when you modify this file. + +# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. +# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } + +# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. +# Rails.backtrace_cleaner.remove_silencers! diff --git a/config/initializers/cdn.rb b/config/initializers/cdn.rb new file mode 100644 index 0000000..133e044 --- /dev/null +++ b/config/initializers/cdn.rb @@ -0,0 +1,11 @@ +if FirstBargain::Application.config.cdn_enabled + ActionController::Base.asset_host = Proc.new do |source, request| + if source == true || request == false || source =~ /jquery/ + nil + else + if request.ssl? then nil + else "http://cdn%d.firstbargain.com" % (source.hash % 4) + end + end + end +end \ No newline at end of file diff --git a/config/initializers/field_with_errors.rb b/config/initializers/field_with_errors.rb new file mode 100644 index 0000000..3ba57e9 --- /dev/null +++ b/config/initializers/field_with_errors.rb @@ -0,0 +1,8 @@ +module ActionView + class Base + def self.field_error_proc + Proc.new { |html_tag, instance| html_tag } + end + end +end + diff --git a/config/initializers/hoptoad.rb b/config/initializers/hoptoad.rb new file mode 100644 index 0000000..4dabd58 --- /dev/null +++ b/config/initializers/hoptoad.rb @@ -0,0 +1,3 @@ +HoptoadNotifier.configure do |config| + config.api_key = ENV["HOPTOAD_KEY"] +end diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..d531b8b --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,10 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format +# (all these examples are active by default): +# ActiveSupport::Inflector.inflections do |inflect| +# inflect.plural /^(ox)$/i, '\1en' +# inflect.singular /^(ox)en/i, '\1' +# inflect.irregular 'person', 'people' +# inflect.uncountable %w( fish sheep ) +# end diff --git a/config/initializers/mime_types.rb b/config/initializers/mime_types.rb new file mode 100644 index 0000000..da902f4 --- /dev/null +++ b/config/initializers/mime_types.rb @@ -0,0 +1,5 @@ +# Be sure to restart your server when you modify this file. + +# Add new mime types for use in respond_to blocks: +# Mime::Type.register "text/richtext", :rtf +# Mime::Type.register_alias "text/html", :iphone \ No newline at end of file diff --git a/config/initializers/money_extension.rb b/config/initializers/money_extension.rb new file mode 100644 index 0000000..6e34291 --- /dev/null +++ b/config/initializers/money_extension.rb @@ -0,0 +1,39 @@ +# This code was not produced by FirstBargain. I found it somewhere on the web, but I cannot find the original author. + +require 'money' + +module ActiveRecord #:nodoc: + module Acts #:nodoc: + module Money #:nodoc: + module ClassMethods + def money(name, options = {}) + allow_nil = options.has_key?(:allow_nil) ? options.delete(:allow_nil) : true + options = {:cents => "#{name}_in_cents".to_sym }.merge(options) + mapping = [[options[:cents], 'cents']] + mapping << [options[:currency].to_s, 'currency'] if options[:currency] + composed_of name, :class_name => 'Money', :mapping => mapping, :allow_nil => allow_nil, + :converter => lambda{ |m| + if !allow_nil && m.nil? + currency = options[:currency] || ::Money.default_currency + m = ::Money.new(0, currency) + end + m.to_money + }, + :constructor => lambda{ |*args| + cents, currency = args + cents ||= 0 + currency ||= ::Money.default_currency + ::Money.new(cents, currency) + } + + define_method "#{name}_with_cleanup=" do |amount| + send "#{name}_without_cleanup=", amount.blank? ? nil : amount.to_money + end + alias_method_chain "#{name}=", :cleanup + end + end + end + end +end + +ActiveRecord::Base.extend ActiveRecord::Acts::Money::ClassMethods diff --git a/config/initializers/redis.rb b/config/initializers/redis.rb new file mode 100644 index 0000000..a9de7c5 --- /dev/null +++ b/config/initializers/redis.rb @@ -0,0 +1 @@ +$redis = Redis.new(:host => 'localhost', :port => 6379) \ No newline at end of file diff --git a/config/initializers/secret_token.rb b/config/initializers/secret_token.rb new file mode 100644 index 0000000..c2efbb1 --- /dev/null +++ b/config/initializers/secret_token.rb @@ -0,0 +1,7 @@ +# Be sure to restart your server when you modify this file. + +# Your secret key for verifying the integrity of signed cookies. +# If you change this key, all old signed cookies will become invalid! +# Make sure the secret is at least 30 characters and all random, +# no regular words or you'll be exposed to dictionary attacks. +FirstBargain::Application.config.secret_token = ENV["SECRET_TOKEN"] diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb new file mode 100644 index 0000000..59bf339 --- /dev/null +++ b/config/initializers/session_store.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +FirstBargain::Application.config.session_store :cookie_store, :key => '_FirstBargain_session' + +# Use the database for sessions instead of the cookie-based default, +# which shouldn't be used to store highly confidential information +# (create the session table with "rake db:sessions:create") +# FirstBargain::Application.config.session_store :active_record_store diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..4ae9e49 --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,136 @@ +# Sample localization file for English. Add more files in this directory for other locales. +# See http://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. + +en: + authlogic: + error_messages: + login_invalid: "should use only letters and numbers please." + date: + order: + - :month + - :day + - :year + activemodel: + errors: + models: + invitation: + attributes: + emails: + invalid: "are not valid" + length: "may be entered up to five at a time" + activerecord: + models: + bid_bot: "Bid Assistant" + errors: + models: + bid_bot: + attributes: + base: + active_bot_limit: "You may only activate one bid assistant at a time." + bids_left: + not_in_range: "must be between 3 and 50." + need_more_bids: "is incorrect. You don't have enough Bid Credits left in your account." + bid_from: + greater_than_or_equal_to: "price must be greater than or equal to 0." + account: + attributes: + base: + ip_taken: "Your IP seems to be registered with another account. We only permit one account per household." + email: + invalid: "domain is banned." + birth_date: + invalid: "must be greater than 18 years ago" + username: + limited: "can only be changed once a month." + auction: + attributes: + ending_at: + past: "must be in the future" + coupon_use: + attributes: + coupon_id: + taken: "has already been used by you" + blank: "is invalid" + auction_order: + attributes: + base: + did_not_win: "You did not win this auction." + already_redeemed: "This auction was already redeemed." + expired: "Sorry, auctions over 7 days old cannot be redeemed." + reward_order: + attributes: + point_discount: + invalid: "is not correct" + buy_now_order: + attributes: + auction: + invalid: "is not eligible for BuyNow. You may have just won this auction, or the 24-hour time frame to BuyNow may have expired." + bid: + attributes: + base: + daily_active_auctions_limit: "Please wait until one of the auctions you are currently participating in has ended. By placing a bid on this item, you might exceed your daily 3 win limit." + monthly_active_auctions_limit: "Please wait until one of the auctions you are currently participating in has ended. By placing a bid on this item, you might exceed your monthly 10 win limit." + auction_ended: "This auction has ended." + need_more_bids: "You don't have any bids left. Please purchase bid credits to participate in an auction." + bid_twice: "You just placed a bid; you're currently the highest bidder." + daily_win_limit_reached: "You've reached your daily win limit. FirstBargain allows customers to win up to 3 times a day. This gives everyone a fair chance to win." + monthly_win_limit_reached: "You've reached your monthly win limit. FirstBargain allows customers to win up to 10 times a month. This gives everyone a fair chance to win." + buy_now_used: "You've already exercised the 'Buy Now' option." + item_too_expensive: "Only 1 win of the same product with a retail price over $200 is allowed per calendar month." + investment: + overinvested: "It would be cheaper for you to 'Buy Now' this item than to continue bidding on it." + messages: + invalid: "contains bad characters or isn't formatted correctly." + mx_invalid: "domain doesn't seem to exist. Check your spelling." + time: + formats: + short_date_time: "%m/%d/%y - %I:%M%p" + order: "%m/%d/%y at %I:%M%p" + admin: "%m/%d/%y - %I:%M:%S%p" + auction: "%m/%d %I:%M %p" + bid: "%r" + attributes: + credits: "Bids" + bonuses: "Bonus Bids" + birth_date: "Date of birth" + registration_ip: "Registration IP" + current_login_ip: "Current login IP" + bids_left: "Number of bids" + bids: + beginner_limit: "You can only bid on one beginner auction at a time." + not_beginner: "Beginner auctions are reserved for customers who have not won anything yet." + flash: + account: + created: "Thank you for registering. Please check your email to verify your account." + updated: "Account updated!" + activations: + activated: "Thank you for verifying your account." + account_not_found: "Invalid verification code. If you think this is a mistake, contact us." + already_verified: "Your account is already verified." + created: "Activation email was resent. Check your spam folder if needed." + email_flagged: "We couldn't resend your activation link because your email address is flagged. Please contact us at support@firstbargain.com for further help, and add us to your contact list to ensure we can reach you." + addresses: + created: "Address saved!" + deleted: "Address removed." + bids: + without_xhr: "You made a bid successfully, but it seems you don't have JavaScript fully enabled. Please check your JavaScript configuration." + contact: + created: "Thank you for contacting us! We will get back to you within 24 hours." + email_flagged: "We could not receive your message because the email address you provided is either invalid or has blacklisted us for spam. Please provide a different email, or use your own email program to send us a message. Sorry for the inconvenience." + coupons: + created: "You got %{count} bonus bids!" + invitations: + created: "Invitations sent" + email_flagged: "We couldn't deliver your invites. Some of the emails you entered either do not exist or have strict spam filters. Please share your invitation link manually." + password_reset: + no_account: "No user was found with that email address." + sent: "Instructions to reset your password have been emailed to you." + success: "Password successfully updated" + expired: "Your reset request has expired. Try requesting another reset." + email_flagged: "Your email address is flagged; please contact us at support@firstbargain.com directly and add us to your contact list to ensure we can reach you." + session: + expired_on_registration: "Sorry, but your session has expired. Care to try again?" + expired: "Your login session has expired. Please try your last action again." + expired_order: "Your session has expired. Please try re-adding your item." + must_be_logged_out: "You must be logged out to access this page." + deleted: "You've successfully logged out. Goodbye." \ No newline at end of file diff --git a/config/newrelic.yml b/config/newrelic.yml new file mode 100644 index 0000000..2bb1aea --- /dev/null +++ b/config/newrelic.yml @@ -0,0 +1,233 @@ +# +# This file configures the New Relic RPM Agent. New Relic RPM monitors +# Rails and Java applications with deep visibility and low overhead. For more +# information, visit www.newrelic.com. +# +# Generated August 15, 2010 +# +# This configuration file is custom generated for Expedient Shopping + +# Here are the settings that are common to all environments: +common: &default_settings + # ============================== LICENSE KEY =============================== + + # You must specify the license key associated with your New Relic + # account. This key binds your Agent's data to your account in the + # New Relic RPM service. + license_key: 'SECRET' + + # Agent Enabled (Rails Only) + # Use this setting to force the agent to run or not run. + # Default is 'auto' which means the agent will install and run only + # if a valid dispatcher such as Mongrel is running. This prevents + # it from running with Rake or the console. Set to false to + # completely turn the agent off regardless of the other settings. + # Valid values are true, false and auto. + # agent_enabled: auto + + # Application Name + # Set this to be the name of your application as you'd like it show + # up in RPM. RPM will then auto-map instances of your application + # into a RPM "application" on your home dashboard page. If you want + # to map this instance into multiple apps, like "AJAX Requests" and + # "All UI" then specify a semicolon separated list of up to three + # distinct names. If you comment this out, it defaults to the + # capitalized RAILS_ENV (i.e., Production, Staging, etc) + #app_name: My Application + + # When "true", the agent collects performance data about your + # application and reports this data to the NewRelic RPM service at + # newrelic.com. This global switch is normally overridden for each + # environment below. (formerly called 'enabled') + monitor_mode: true + + # Developer mode should be off in every environment but + # development as it has very high overhead in memory. + developer_mode: false + + # The newrelic agent generates its own log file to keep its logging + # information separate from that of your application. Specify its + # log level here. + log_level: info + + # The newrelic agent communicates with the RPM service via http by + # default. If you want to communicate via https to increase + # security, then turn on SSL by setting this value to true. Note, + # this will result in increased CPU overhead to perform the + # encryption involved in SSL communication, but this work is done + # asynchronously to the threads that process your application code, + # so it should not impact response times. + ssl: false + + # EXPERIMENTAL: enable verification of the SSL certificate sent by + # the server. This setting has no effect unless SSL is enabled + # above. This may block your application. Only enable it if the data + # you send us needs end-to-end verified certificates. + # + # This means we cannot cache the DNS lookup, so each request to the + # RPM service will perform a lookup. It also means that we cannot + # use a non-blocking lookup, so in a worst case, if you have DNS + # problems, your app may block indefinitely. + # verify_certificate: true + + # Set your application's Apdex threshold value with the 'apdex_t' + # setting, in seconds. The apdex_t value determines the buckets used + # to compute your overall Apdex score. + # Requests that take less than apdex_t seconds to process will be + # classified as Satisfying transactions; more than apdex_t seconds + # as Tolerating transactions; and more than four times the apdex_t + # value as Frustrating transactions. + # For more about the Apdex standard, see + # http://support.newrelic.com/faqs/general/apdex + + apdex_t: 0.5 + + # Proxy settings for connecting to the RPM server. + # + # If a proxy is used, the host setting is required. Other settings + # are optional. Default port is 8080. + # + # proxy_host: hostname + # proxy_port: 8080 + # proxy_user: + # proxy_pass: + + + # Tells transaction tracer and error collector (when enabled) + # whether or not to capture HTTP params. When true, frameworks can + # exclude HTTP parameters from being captured. + # Rails: the RoR filter_parameter_logging excludes parameters + # Java: create a config setting called "ignored_params" and set it to + # a comma separated list of HTTP parameter names. + # ex: ignored_params: credit_card, ssn, password + capture_params: false + + + # Transaction tracer captures deep information about slow + # transactions and sends this to the RPM service once a + # minute. Included in the transaction is the exact call sequence of + # the transactions including any SQL statements issued. + transaction_tracer: + + # Transaction tracer is enabled by default. Set this to false to + # turn it off. This feature is only available at the Silver and + # above product levels. + enabled: true + + # Threshold in seconds for when to collect a transaction + # trace. When the response time of a controller action exceeds + # this threshold, a transaction trace will be recorded and sent to + # RPM. Valid values are any float value, or (default) "apdex_f", + # which will use the threshold for an dissatisfying Apdex + # controller action - four times the Apdex T value. + transaction_threshold: apdex_f + + # When transaction tracer is on, SQL statements can optionally be + # recorded. The recorder has three modes, "off" which sends no + # SQL, "raw" which sends the SQL statement in its original form, + # and "obfuscated", which strips out numeric and string literals + record_sql: obfuscated + + # Threshold in seconds for when to collect stack trace for a SQL + # call. In other words, when SQL statements exceed this threshold, + # then capture and send to RPM the current stack trace. This is + # helpful for pinpointing where long SQL calls originate from + stack_trace_threshold: 0.500 + + # Determines whether the agent will capture query plans for slow + # SQL queries. Only supported in mysql and postgres. Should be + # set to false when using other adapters. + # explain_enabled: true + + # Threshold for query execution time below which query plans will not + # not be captured. Relevant only when `explain_enabled` is true. + # explain_threshold: 0.5 + + # Error collector captures information about uncaught exceptions and + # sends them to RPM for viewing + error_collector: + + # Error collector is enabled by default. Set this to false to turn + # it off. This feature is only available at the Silver and above + # product levels + enabled: true + + # Rails Only - tells error collector whether or not to capture a + # source snippet around the place of the error when errors are View + # related. + capture_source: true + + # To stop specific errors from reporting to RPM, set this property + # to comma separated values. Default is to ignore routing errors + # which are how 404's get triggered. + # + ignore_errors: ActionController::RoutingError + + # (Advanced) Uncomment this to ensure the cpu and memory samplers + # won't run. Useful when you are using the agent to monitor an + # external resource + # disable_samplers: true + + # If you aren't interested in visibility in these areas, you can + # disable the instrumentation to reduce overhead. + # + # disable_view_instrumentation: true + # disable_activerecord_instrumentation: true + # disable_memcache_instrumentation: true + # disable_dj: true + + # Certain types of instrumentation such as GC stats will not work if + # you are running multi-threaded. Please let us know. + # multi_threaded = false + +# Application Environments +# ------------------------------------------ +# Environment specific settings are in this section. +# For Rails applications, RAILS_ENV is used to determine the environment +# For Java applications, pass -Dnewrelic.environment to set +# the environment + +# NOTE if your application has other named environments, you should +# provide newrelic configuration settings for these environments here. + +development: + <<: *default_settings + # Turn off communication to RPM service in development mode (also + # 'enabled'). + # NOTE: for initial evaluation purposes, you may want to temporarily + # turn the agent on in development mode. + monitor_mode: false + + # Rails Only - when running in Developer Mode, the New Relic Agent will + # present performance information on the last 100 transactions you have + # executed since starting the mongrel. + # NOTE: There is substantial overhead when running in developer mode. + # Do not use for production or load testing. + developer_mode: true + + # Enable textmate links + textmate: true + + # Needed for Pow! server + #agent_enabled: true + +test: + <<: *default_settings + # It almost never makes sense to turn on the agent when running + # unit, functional or integration tests or the like. + monitor_mode: false + +# Turn on the agent in production for 24x7 monitoring. NewRelic +# testing shows an average performance impact of < 5 ms per +# transaction, you you can leave this on all the time without +# incurring any user-visible performance degradation. +production: + <<: *default_settings + monitor_mode: true + +# Many applications have a staging environment which behaves +# identically to production. Support for that environment is provided +# here. By default, the staging environment has the agent turned on. +staging: + <<: *default_settings + monitor_mode: false diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..ddd2e17 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,80 @@ +FirstBargain::Application.routes.draw do + + get 'poller' => 'poller#index' + get 'poller/:id' => 'poller#show' + get 'promos' => 'widget#index' + get 'promos/:id' => "widget#show" + + post "orders/ccbill" => "ccbill#create" + + resources :auctions, only: [:index, :show] do + resources :bids, only: :create + resource :bid_bot, only: :create + get :winners, on: :collection + end + + resources :orders, :except => [:show, :destroy] do + post :confirm, on: :collection + get :paypal, on: :collection + get :success, on: :collection + get :failure, on: :collection + end + + resources :bookmarks, only: [:index, :create, :destroy] + resources :addresses, :except => [:show, :update, :edit] + resources :invitations, only: [:index, :create] + get 'bids' => 'bid_packs#new' + resources :products, only: [:index, :show] + resources :coupons, only: [:new, :create] + resources :landings, only: :show do + get :promo, on: :collection + get :category, on: :member + end + + resource :session, only: [:new, :create, :destroy] + resource :account, :except => :destroy do + get :welcome + end + resource :password_reset, :except => [:destroy, :show] + resource :contact, only: [:show, :create] + resource :activation, only: [:new, :create] + + resource :splash, only: [:show, :create] + + namespace :admin do + resources :featured_auctions, :products, :auctions, :coupons, :categories, :analytics + resources :orders do + put :ship, on: :member + put :void, on: :member + put :approve, on: :member + put :refund, on: :member + end + resources :accounts do + put :adjust, on: :member + put :flag, on: :member + put :subscribe, on: :member + get :online, on: :collection + end + root :to => "auctions#index" + end + + get 'privacy' => 'static#privacy' + get 'about' => 'static#about' + get 'tutorial' => 'static#tutorial' + get 'tips' => 'static#tips' + get 'tos' => 'static#tos' + get 'returns' => 'static#returns' + get 'rewards' => 'static#rewards' + get 'guarantee' => 'static#guarantee' + get 'rules' => 'static#rules' + + get 'faq/new_user' => 'static#faq_new_user' + get 'faq/auctions' => 'static#faq_auctions' + get 'faq/account' => 'static#faq_account' + get 'faq/shipping' => 'static#faq_shipping' + get 'faq/payment' => 'static#faq_payment' + get 'faq' => 'static#faq' + + root :to => "auctions#index" + +end diff --git a/config/schedule.rb b/config/schedule.rb new file mode 100644 index 0000000..be44fb1 --- /dev/null +++ b/config/schedule.rb @@ -0,0 +1,41 @@ +# Use this file to easily define all of your cron jobs. +# +# It's helpful, but not entirely necessary to understand cron before proceeding. +# http://en.wikipedia.org/wiki/Cron + +# Example: +# +# set :output, "/path/to/my/cron_log.log" +# +# every 2.hours do +# command "/usr/bin/some_great_command" +# runner "MyModel.some_method" +# rake "some:great:rake:task" +# end +# +# every 4.days do +# runner "AnotherModel.prune_old_records" +# end + +# Learn more: http://github.com/javan/whenever + +## Email daily report at 12:01 am (Linux time zone, which is PT) +every 1.days, :at => "12:01 am" do + runner "StaffMailer.daily_activity_report.deliver" +end + +## Email weekly report at 12:01 am on Sunday (Linux time zone, which is PT) +every :sunday, :at => "12:01 am" do + runner "StaffMailer.weekly_activity_report.deliver" +end + +## Sync Mailchimp at 12:03 AM PT +every 1.days, :at => "12:03 am" do + runner "Account.sync_mailchimp" +end + +## Expire Redis bid bot jobs cache +every 1.days, :at => "1:00 am" do + runner "Auction.expire_redis_job_cache_for_last_24_hours" +end + diff --git a/config/stalker_jobs.rb b/config/stalker_jobs.rb new file mode 100644 index 0000000..372a26a --- /dev/null +++ b/config/stalker_jobs.rb @@ -0,0 +1,40 @@ +require File.expand_path("../environment", __FILE__) +require 'net/http' + +job "bid_bot" do |args| + if $redis.sismember("auction_#{args['id']}_job_ids", args["redis_job_id"]) + a = Auction.find(args["id"]) + BidBot.pool(a).any? do |bot| + bot.bid! + end + end +end + +job "emails.won_auction" do |args| + a = Auction.find(args["id"]) + if a.finished? + CustomerMailer.won_auction(args["id"]).deliver if a.account_id? + else + t = a.ending_at + 7.minutes + Stalker.enqueue("emails.won_auction", args, {delay: (t - Time.now).round}) + end +end + +job "emails.customer" do |args| + begin + m = CustomerMailer.public_send(args["method"], args["params"]) + m.deliver + rescue Net::SMTPFatalError + Account.find_by_email(m.to.first).try(:update_attribute, :good_email, false) + end +end + +job "emails.contact_form" do |hash| + StaffMailer.inquiry(hash).deliver +end + +# CCBill shipment confirmations +job "Order" do |args| + o = Order.find(args["order_id"]) + o.create_fulfillment! if o.requires_shipping? +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..bcca518 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,285 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# Note that this schema.rb definition is the authoritative source for your +# database schema. If you need to create the application database on another +# system, you should be using db:schema:load, not running all the migrations +# from scratch. The latter is a flawed and unsustainable approach (the more migrations +# you'll amass, the slower it'll run and the greater likelihood for issues). +# +# It's strongly recommended to check this file into your version control system. + +ActiveRecord::Schema.define(:version => 20110802152801) do + + create_table "accounts", :force => true do |t| + t.integer "credits", :default => 0 + t.integer "bonuses", :default => 0 + t.integer "points_in_cents", :default => 0 + t.date "birth_date" + t.boolean "verified", :default => false + t.string "username", :null => false + t.string "email", :null => false + t.string "encrypted_password", :null => false + t.string "password_salt", :null => false + t.string "persistence_token", :null => false + t.string "single_access_token", :null => false + t.string "perishable_token", :null => false + t.datetime "created_at" + t.datetime "updated_at" + t.integer "parent_id" + t.boolean "has_purchased", :default => false + t.integer "cumulative_credits", :default => 0 + t.integer "cumulative_bonuses", :default => 0 + t.boolean "active", :default => true + t.string "registration_ip" + t.string "current_login_ip" + t.string "last_login_ip" + t.datetime "last_username_change" + t.boolean "good_email", :default => true + t.string "source" + t.datetime "last_request_at" + t.text "notes" + t.boolean "subscribed", :default => false, :null => false + t.string "utm_medium" + t.string "utm_source" + t.string "utm_campaign" + t.string "utm_term" + t.string "utm_content" + t.boolean "bids_purchased", :default => false + end + + add_index "accounts", ["email"], :name => "index_accounts_on_email", :unique => true + add_index "accounts", ["perishable_token"], :name => "index_accounts_on_perishable_token", :unique => true + add_index "accounts", ["persistence_token"], :name => "index_accounts_on_persistence_token", :unique => true + add_index "accounts", ["registration_ip"], :name => "index_accounts_on_registration_ip" + add_index "accounts", ["single_access_token"], :name => "index_accounts_on_single_access_token", :unique => true + add_index "accounts", ["username"], :name => "index_accounts_on_login", :unique => true + + create_table "addresses", :force => true do |t| + t.string "name" + t.string "address" + t.string "address_2" + t.string "city" + t.string "state" + t.string "zip" + t.string "country", :default => "US" + t.string "phone" + t.datetime "created_at" + t.datetime "updated_at" + t.integer "account_id" + t.string "label" + end + + add_index "addresses", ["account_id"], :name => "index_addresses_on_account_id" + + create_table "approvals", :force => true do |t| + t.string "ip" + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "approvals", ["ip"], :name => "index_approvals_on_ip", :unique => true + + create_table "auctions", :force => true do |t| + t.integer "product_id" + t.integer "account_id" + t.datetime "ending_at" + t.integer "price_increment_in_cents", :default => 1 + t.datetime "created_at" + t.datetime "updated_at" + t.boolean "redeemed", :default => false + t.integer "going_price_in_cents", :default => 0 + t.boolean "hot", :default => false + t.integer "retail_price_in_cents" + t.boolean "is_buy_now", :default => false + t.integer "timer_reset", :default => 30 + t.integer "investment_id" + t.boolean "beginner", :default => false + t.boolean "finished", :default => false, :null => false + end + + add_index "auctions", ["account_id"], :name => "index_auctions_on_account_id" + add_index "auctions", ["ending_at"], :name => "index_auctions_on_ending_at" + + create_table "bid_bots", :force => true do |t| + t.integer "account_id" + t.integer "auction_id" + t.integer "bid_from_in_cents", :default => 0 + t.integer "bids_left" + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "bid_bots", ["auction_id", "account_id"], :name => "index_bid_bots_on_auction_id_and_account_id", :unique => true + add_index "bid_bots", ["auction_id", "bids_left", "bid_from_in_cents", "account_id"], :name => "by_pool" + + create_table "bids", :force => true do |t| + t.integer "account_id" + t.integer "auction_id" + t.datetime "created_at" + t.datetime "updated_at" + t.boolean "paid", :default => true + t.string "username" + t.boolean "botted", :default => false + end + + add_index "bids", ["auction_id"], :name => "index_bids_on_auction_id" + + create_table "bookmarks", :force => true do |t| + t.integer "account_id" + t.integer "auction_id" + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "bookmarks", ["account_id"], :name => "index_bookmarks_on_account_id" + + create_table "categories", :force => true do |t| + t.string "name" + t.datetime "created_at" + t.datetime "updated_at" + end + + create_table "coupon_uses", :force => true do |t| + t.integer "account_id" + t.integer "coupon_id" + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "coupon_uses", ["account_id", "coupon_id"], :name => "index_coupon_uses_on_account_id_and_coupon_id", :unique => true + + create_table "coupons", :force => true do |t| + t.string "code" + t.string "summary" + t.datetime "ends_at" + t.datetime "created_at" + t.datetime "updated_at" + t.integer "bonuses" + t.integer "uses_left" + end + + add_index "coupons", ["code"], :name => "index_coupons_on_code" + + create_table "featured_auctions", :force => true do |t| + t.integer "auction_id" + t.string "name" + t.text "description" + t.string "image_url" + t.datetime "created_at" + t.datetime "updated_at" + end + + create_table "investments", :force => true do |t| + t.integer "account_id" + t.integer "amount_in_cents", :default => 0 + t.integer "credits_used", :default => 0 + t.datetime "created_at" + t.datetime "updated_at" + t.integer "auction_id" + t.boolean "expired", :default => false + t.integer "bonuses_used", :default => 0 + end + + add_index "investments", ["account_id", "auction_id"], :name => "index_investments_on_account_id_and_auction_id", :unique => true + + create_table "orders", :force => true do |t| + t.string "state", :default => "pending" + t.integer "account_id" + t.string "ip_address" + t.string "first_name" + t.string "last_name" + t.string "card_type" + t.date "card_expires_on" + t.datetime "created_at" + t.datetime "updated_at" + t.datetime "shipped_at" + t.string "confirmation" + t.string "shipping_name" + t.string "shipping_address" + t.string "shipping_address_2" + t.string "shipping_city" + t.string "shipping_state" + t.string "shipping_country", :default => "US" + t.string "shipping_phone" + t.string "billing_address" + t.string "billing_address_2" + t.string "billing_city" + t.string "billing_state" + t.string "billing_country", :default => "US" + t.string "billing_phone" + t.string "shipping_zip" + t.string "billing_zip" + t.string "express_token" + t.string "express_payer_id" + t.integer "subtotal_in_cents" + t.integer "shipping_price_in_cents" + t.integer "point_discount_in_cents" + t.integer "buyable_id" + t.string "type" + t.integer "sales_tax_in_cents", :default => 0 + t.string "tracking_id", :default => "" + t.string "shipping_company", :default => "" + end + + add_index "orders", ["account_id"], :name => "index_orders_on_account_id" + add_index "orders", ["state"], :name => "index_orders_on_state" + + create_table "pictures", :force => true do |t| + t.integer "product_id" + t.string "data" + t.string "summary" + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "pictures", ["product_id"], :name => "index_pictures_on_product_id" + + create_table "products", :force => true do |t| + t.string "name" + t.string "summary" + t.text "description" + t.integer "retail_price_in_cents", :default => 0 + t.string "main_picture" + t.datetime "created_at" + t.datetime "updated_at" + t.integer "shipping_price_in_cents", :default => 0 + t.integer "max_discount_in_cents", :default => 0 + t.boolean "visible", :default => true + t.integer "bonuses", :default => 0 + t.boolean "requires_shipping", :default => true + t.integer "category_id" + t.boolean "widget_worthy", :default => false + t.integer "tax_in_cents", :default => 0 + t.integer "cost_in_cents", :default => 0 + t.boolean "discontinued", :default => false + end + + add_index "products", ["category_id"], :name => "index_products_on_category_id" + add_index "products", ["visible"], :name => "index_products_on_visible" + + create_table "transactions", :force => true do |t| + t.integer "order_id" + t.integer "amount_in_cents", :default => 0 + t.boolean "success" + t.string "authorization" + t.string "message" + t.string "action" + t.text "params" + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "transactions", ["order_id"], :name => "index_transactions_on_order_id" + + create_table "viewers", :force => true do |t| + t.string "login" + t.string "crypted_password" + t.string "password_salt" + t.string "persistence_token" + t.datetime "created_at" + t.datetime "updated_at" + end + +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 0000000..10a7ef0 --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,8 @@ +# This file should contain all the record creation needed to seed the database with its default values. +# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). +# +# Examples: +# +# cities = City.create([{ :name => 'Chicago' }, { :name => 'Copenhagen' }]) +# Mayor.create(:name => 'Daley', :city => cities.first) +Factory :featured_auction \ No newline at end of file diff --git a/doc/CCBill_Background_Post_Users_Guide.pdf b/doc/CCBill_Background_Post_Users_Guide.pdf new file mode 100644 index 0000000..73bc435 Binary files /dev/null and b/doc/CCBill_Background_Post_Users_Guide.pdf differ diff --git a/doc/CCBill_SMS_Users_Guide.pdf b/doc/CCBill_SMS_Users_Guide.pdf new file mode 100644 index 0000000..cd06265 Binary files /dev/null and b/doc/CCBill_SMS_Users_Guide.pdf differ diff --git a/doc/README_FOR_APP b/doc/README_FOR_APP new file mode 100644 index 0000000..fe41f5c --- /dev/null +++ b/doc/README_FOR_APP @@ -0,0 +1,2 @@ +Use this README file to introduce your application and point to useful places in the API for learning more. +Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries. diff --git a/doc/SMS_Addendum_Subscription_Tangibles.pdf b/doc/SMS_Addendum_Subscription_Tangibles.pdf new file mode 100644 index 0000000..bc7959e Binary files /dev/null and b/doc/SMS_Addendum_Subscription_Tangibles.pdf differ diff --git a/lib/authorize_net.rb b/lib/authorize_net.rb new file mode 100644 index 0000000..6595b8c --- /dev/null +++ b/lib/authorize_net.rb @@ -0,0 +1,76 @@ +module AuthorizeNet + + module ClassMethods + attr_accessor :card_number, :card_verification + before_validation :set_shipping_from_billing + validate :validate_card, on: :create, :unless => :paypal? + validates :billing_phone, :billing_address, :billing_city, :billing_state, :billing_zip, :presence => true, :unless => :paypal?, on: :create + validates :shipping_name, :shipping_phone, :shipping_address, :shipping_city, :shipping_state, :shipping_zip, presence: true, if: -> {requires_shipping? and not paypal?}, on: :create + end + + def self.included(klass) + klass.class_eval do + private :set_shipping_from_billing, :validate_card, :standard_purchase_options + end + end + + def set_shipping_from_billing + if different_shipping == "0" and not paypal? + %w[name address address_2 city state zip country phone].each do |sym| + b = public_send("billing_#{sym}") + public_send("shipping_#{sym}=", b) + end + end + end + + def validate_card + credit_card.errors.full_messages.each {|msg| errors[:base] << msg} if credit_card.invalid? + end + + def credit_card + @credit_card ||= ActiveMerchant::Billing::CreditCard.new( + :type => card_type, + :number => card_number, + :verification_value => card_verification, + :month => card_expires_on.try(:month), + :year => card_expires_on.try(:year), + :first_name => first_name, + :last_name => last_name + ) + end + + def standard_purchase_options + b = { + :name => billing_name, + :address1 => billing_address, + :address2 => billing_address_2, + :city => billing_city, + :state => billing_state, + :zip => billing_zip, + :country => billing_country, + :phone => billing_phone + } + s = if requires_shipping? then { + :name => shipping_name, + :address1 => shipping_address, + :address2 => shipping_address_2, + :city => shipping_city, + :state => shipping_state, + :zip => shipping_zip, + :country => shipping_country, + :phone => shipping_phone + } + else b + end + { + :order_id => id, + :ip => ip_address, + :customer => account.username, + :description => contents, + :email => account.email, + :billing_address => b, + :shipping_address => s + } + end + +end \ No newline at end of file diff --git a/lib/ccbill.rb b/lib/ccbill.rb new file mode 100644 index 0000000..4d916cd --- /dev/null +++ b/lib/ccbill.rb @@ -0,0 +1,115 @@ +require 'digest/md5' +require 'net/https' + +module CCBill + CCBILL_PACKS = {30 => "9133", 50 => "6048", 100 => "3969", 200 => "3725"}.freeze + + def ccbill_url + p = { + :clientAccnum => "942370", + :uid => account.single_access_token, + :buyable => "#{kind}-#{buyable_id}", + :email => account.email, + :customTaxPrice => sales_tax.to_f, + :customShippingPrice => shipping_price.to_f, + :customOrderId => (1 + rand(999998)), + :customSkuCode => buyable_id, + :customProductName => contents, + :customUnitPrice => subtotal.to_f, + :customQuantity => 1, + :referer => "organic", + } + if is_a? BidOrder + p[:clientSubacc] = "0000" + p[:formName] = "942370-0000cc-1" + p[:allowedTypes] = CCBILL_PACKS[buyable_id] + else + p[:clientSubacc] = "0001" + p[:formName] = "942370-0001cc-1" + p[:formPrice] = total_price.to_f + p[:formPeriod] = "2" + p[:currencyCode] = "840" + p[:formDigest] = Digest::MD5.hexdigest("#{total_price.to_f}#{p[:formPeriod]}#{p[:currencyCode]}NLMX8fmxaROkppOElM27fTbE") + end + if requires_shipping? + p[:shipping_name] = shipping_name + p[:shipping_address] = shipping_address + p[:shipping_address_2] = shipping_address_2 + p[:shipping_city] = shipping_city + p[:shipping_state] = shipping_state + p[:shipping_country] = shipping_country + p[:shipping_phone] = shipping_phone + p[:shipping_zip] = shipping_zip + p[:customer_fname] = shipping_name.split.first + p[:customer_lname] = shipping_name.split.last + p[:address1] = shipping_address_2.blank? ? shipping_address : "#{shipping_address} #{shipping_address_2}" + p[:city] = shipping_city + p[:state] = shipping_state + p[:zipcode] = shipping_zip + p[:country] = shipping_country + p[:phone_number] = shipping_phone + end + "https://bill.ccbill.com/jpost/signup.cgi?#{p.to_query}" + end + + def process_postback(postback) + success = postback["reasonForDecline"].blank? + message = (success ? "Thank you!" : postback["reasonForDecline"]) + options = { + :authorization => postback["subscription_id"], + :fraud_review => false, + :avs_result => {}, + :cvv_result => '' + } + ActiveMerchant::Billing::Response.new(success, message, postback, options) + end + + def create_fulfillment! + p = { + :transactionId => transactions.first.authorization, + :shippingCompany => shipping_company, + :trackingId => tracking_id, + :action => "createFulfillment", + :clientAccnum => "942370", + :usingSubacc => "0001", + :username => "1stbargn", + :password => "mybargn1" + } + req = Net::HTTP::Get.new "https://datalink.ccbill.com/utils/subscriptionManagement.cgi?#{p.to_query}" + con = Net::HTTP.new "datalink.ccbill.com", 443 + con.use_ssl = true + con.start {|http| http.request req} + end + + module ClassMethods + def from_ccbill(p) + user = Account.find_by_single_access_token p["uid"] + k, b = p["buyable"].try :split, "-" + params = { + :kind => k,# us + :buyable => b,# us + :ip_address => p["ip_address"], + :first_name => p["customer_fname"], + :last_name => p["customer_lname"], + :card_type => p["cardType"], + :card_expires_on => 20.years.from_now, + :shipping_name => (p["shipping_name"].blank? ? p["customer_fname"] + p["customer_lname"] : p["shipping_name"]),#us + :shipping_address => p["shipping_address"],#us + :shipping_address_2 => p["shipping_address_2"],#us + :shipping_city => p["shipping_city"], #us + :shipping_state => p["shipping_state"],#us + :shipping_country => p["shipping_country"], #us + :shipping_phone => p["shipping_phone"],#us + :billing_address => p["address1"], + :billing_address_2 => "", + :billing_city => p["city"], + :billing_state => p["state"], + :billing_country => p["country"], + :billing_phone => p["phone_number"], + :shipping_zip => p["shipping_zip"], # us + :billing_zip => p["zipcode"], + } + factory(params, user) + end + end +end \ No newline at end of file diff --git a/lib/heartbeat.rb b/lib/heartbeat.rb new file mode 100755 index 0000000..cbd8e9c --- /dev/null +++ b/lib/heartbeat.rb @@ -0,0 +1,87 @@ +#!/usr/bin/env ruby + +require File.expand_path('../../config/environment', __FILE__) +require 'daemon_spawn' +require "fileutils" + +module Heartbeat + + # Generic class for repeated tasks without clock drifting. + # This was found at + # http://soohwan.blogspot.com/2011/02/ruby-periodic-process.html + class Service + def initialize + @interval = 1.0 + @start_time = Time.now + end + def start + # Update the start-time + @start_time = Time.now + # run loop + loop do + t_start = Time.now + # process the job + process + elapsed = Time.now - t_start + if elapsed > @interval + puts "Error: Job is bigger than Interval.. #{elapsed}" + end + # apply some compensation. + compensation = (Time.now - @start_time) % @interval + sleep(@interval - compensation) + end + end + def process + raise NotImplementedError + end + end + + class AuctionEnder < Service + def process # how many auctions ended this cycle + finished = Auction.inactive.where(finished: false).update_all(finished: true) + Rails.cache.increment("finished", finished) + end + + def recover!(period) + t = Time.now + puts "#{t} Entered recovery mode" + t_0 = t - period + auctions = Auction.where(ending_at: t_0..t) + if auctions.size > 0 + src = Rails.root.join("public", "watchdog-recovery.html") + dest = Rails.root.join("public", "system", "maintenance.html") + FileUtils.cp(src, dest) + auctions.each do |a| + a.ending_at += 600 # 10 minutes + a.save + end + Rails.cache.increment("bids") # TODO: better cache key + sleep(1) + FileUtils.rm(dest) + end + puts "#{Time.now} #{auctions.size} auction/s reset" + end + end + + class Runner < DaemonSpawn::Base + def start(args) + a = AuctionEnder.new + if args[0] == "recovery" + a.recover!(args[1].to_i) + end + a.start + end + + def stop + puts "#{Time.now} Manually stopped" + end + end +end + +Heartbeat::Runner.spawn!({ + application: "Heartbeat", + log_file: Rails.root.join("log", "heartbeat.log"), + pid_file: Rails.root.join("tmp", "pids", "heartbeat.pid"), + working_dir: Rails.root, + singleton: true +}) \ No newline at end of file diff --git a/lib/menu_tab_builder.rb b/lib/menu_tab_builder.rb new file mode 100644 index 0000000..2d7837b --- /dev/null +++ b/lib/menu_tab_builder.rb @@ -0,0 +1,14 @@ +class MenuTabBuilder < TabsOnRails::Tabs::TabsBuilder + + def tab_for(tab, name, options, item_options = {}) + # Adds "current" to the li tag + item_options[:class] = item_options[:class].to_s.split(" ").push("current").join(" ") if current_tab?(tab) + #content = @context.link_to_unless(current_tab?(tab), name, options) do + # @context.link_to @context.content_tag(:span, name), options + #end + #title = current_tab?(tab) ? "#{name}".html_safe : name + content = @context.link_to(name, options) # goes inside li + @context.content_tag(:li, content, item_options) + end + +end \ No newline at end of file diff --git a/lib/paypal.rb b/lib/paypal.rb new file mode 100644 index 0000000..d0a7c11 --- /dev/null +++ b/lib/paypal.rb @@ -0,0 +1,61 @@ +module PayPal + + def self.included(klass) + klass.class_eval do + private :setup_paypal_options, :express_purchase_options + end + end + + def process_paypal_purchase! + response = begin + Rails.configuration.paypal.purchase total_price.cents, express_purchase_options + rescue ActiveMerchant::ConnectionError + ActiveMerchant::Billing::Response.new(false, "PayPal dropped the connection.") + end + process_response(response) + end + + def paypal? + gateway == "paypal" || express_token? + end + + def paypal_url(r, c) + response = Rails.configuration.paypal.setup_purchase(total_price.cents, setup_paypal_options(r, c)) + Rails.configuration.paypal.redirect_url_for response.token + end + + def setup_paypal_options(r, c) + { + :return_url => r, + :cancel_return_url => c, + :no_shipping => !requires_shipping?, + :description => contents, + } + end + + def express_purchase_options + { + :token => express_token, + :payer_id => express_payer_id, + :description => contents + } + end + + def express_token=(token) + self[:express_token] = token + if new_record? && token.present? && express_payer_id.blank? + details = Rails.configuration.paypal.details_for token + self.express_payer_id = details.payer_id + self.first_name = details.params["first_name"] + self.last_name = details.params["last_name"] + self.shipping_name = details.address["name"] + self.shipping_address = details.address["address1"] + self.shipping_address_2 = details.address["address2"] + self.shipping_city = details.address["city"] + self.shipping_state = details.address["state"] + self.shipping_zip = details.address["zip"] + self.shipping_phone = details.params["contact_phone"] + end + end + +end \ No newline at end of file diff --git a/lib/stalker_worker.rb b/lib/stalker_worker.rb new file mode 100755 index 0000000..b17fd32 --- /dev/null +++ b/lib/stalker_worker.rb @@ -0,0 +1,23 @@ +#!/usr/bin/env ruby + +# In production and staging, starts 3 workers. + +require File.expand_path('../../config/environment', __FILE__) +require 'daemon_spawn' + +class StalkerWorkerDaemon < DaemonSpawn::Base + def start(args) + exec "stalk config/stalker_jobs.rb" + end + def stop + + end +end + +StalkerWorkerDaemon.spawn!({ + processes: (Rails.env.development? ? 2 : 3), + log_file: Rails.root.join("log", "stalker_worker.log").to_s, # to_s needed here + sync_log: true, + working_dir: Rails.root, + singleton: true +}) \ No newline at end of file diff --git a/lib/tasks/.gitkeep b/lib/tasks/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/lib/tasks/daemons.rake b/lib/tasks/daemons.rake new file mode 100644 index 0000000..f6587f6 --- /dev/null +++ b/lib/tasks/daemons.rake @@ -0,0 +1,6 @@ +# require 'resque/tasks' +# require 'resque_scheduler/tasks' +# +# # load the env so we know about the job classes +# task "resque:setup" => :environment +# task "resque:scheduler_setup" => :environmentrails s diff --git a/lib/tasks/upkeep.rake b/lib/tasks/upkeep.rake new file mode 100644 index 0000000..e744980 --- /dev/null +++ b/lib/tasks/upkeep.rake @@ -0,0 +1,9 @@ +desc 'Expire all buy now prices older than 24 hours' +task :expire_investments => :environment do + Investment.nonexpired.where("updated_at <= ?", Rails.configuration.buy_now_expiration.ago).update_all(expired: true) +end + +desc "Clear the Rails cache" +task :clear_cache => :environment do + Rails.cache.clear +end diff --git a/log/.gitkeep b/log/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/public/404.html b/public/404.html new file mode 100644 index 0000000..f68f90b --- /dev/null +++ b/public/404.html @@ -0,0 +1,70 @@ + + + + The page you were looking for doesn't exist (404) + + + + +
+ +

Oops, the page you were looking for doesn't exist.

+

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

+
+ + \ No newline at end of file diff --git a/public/422.html b/public/422.html new file mode 100644 index 0000000..024bc9a --- /dev/null +++ b/public/422.html @@ -0,0 +1,70 @@ + + + + The change you wanted was rejected (422) + + + + +
+ +

Oops, the change you wanted was rejected.

+

You may have tried to log into another account, but your web browser still has your old account information. Please go back, refresh the page, and try logging in again.

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

Oops, something went wrong.

+

We've been notified about this issue. Our engineers are working on a solution.

+
+ + diff --git a/public/apple-touch-icon-precomposed.png b/public/apple-touch-icon-precomposed.png new file mode 100644 index 0000000..dad6a65 Binary files /dev/null and b/public/apple-touch-icon-precomposed.png differ diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png new file mode 100644 index 0000000..dad6a65 Binary files /dev/null and b/public/apple-touch-icon.png differ diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..da8b67e Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/fonts/embed/AndBasR-webfont.eot b/public/fonts/embed/AndBasR-webfont.eot new file mode 100644 index 0000000..81e33b3 Binary files /dev/null and b/public/fonts/embed/AndBasR-webfont.eot differ diff --git a/public/fonts/embed/AndBasR-webfont.svg b/public/fonts/embed/AndBasR-webfont.svg new file mode 100644 index 0000000..b04166e --- /dev/null +++ b/public/fonts/embed/AndBasR-webfont.svg @@ -0,0 +1,146 @@ + + + + +This is a custom SVG webfont generated by Font Squirrel. +Designer : Annie Olsen and Victor Gaultney +Foundry : SIL International +Foundry URL : http://scripts.sil.org + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/fonts/embed/AndBasR-webfont.ttf b/public/fonts/embed/AndBasR-webfont.ttf new file mode 100644 index 0000000..865fe91 Binary files /dev/null and b/public/fonts/embed/AndBasR-webfont.ttf differ diff --git a/public/fonts/embed/AndBasR-webfont.woff b/public/fonts/embed/AndBasR-webfont.woff new file mode 100644 index 0000000..e3dd0c2 Binary files /dev/null and b/public/fonts/embed/AndBasR-webfont.woff differ diff --git a/public/fonts/embed/ColabLig-webfont.eot b/public/fonts/embed/ColabLig-webfont.eot new file mode 100644 index 0000000..2aa5b99 Binary files /dev/null and b/public/fonts/embed/ColabLig-webfont.eot differ diff --git a/public/fonts/embed/ColabLig-webfont.svg b/public/fonts/embed/ColabLig-webfont.svg new file mode 100644 index 0000000..5a503a3 --- /dev/null +++ b/public/fonts/embed/ColabLig-webfont.svg @@ -0,0 +1,142 @@ + + + + +This is a custom SVG webfont generated by Font Squirrel. +Foundry : This Font is designed by Ralph Oliver du Carrois + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/fonts/embed/ColabLig-webfont.ttf b/public/fonts/embed/ColabLig-webfont.ttf new file mode 100644 index 0000000..98a683e Binary files /dev/null and b/public/fonts/embed/ColabLig-webfont.ttf differ diff --git a/public/fonts/embed/ColabLig-webfont.woff b/public/fonts/embed/ColabLig-webfont.woff new file mode 100644 index 0000000..00e18f2 Binary files /dev/null and b/public/fonts/embed/ColabLig-webfont.woff differ diff --git a/public/fonts/embed/ColabReg-webfont.eot b/public/fonts/embed/ColabReg-webfont.eot new file mode 100644 index 0000000..04cf693 Binary files /dev/null and b/public/fonts/embed/ColabReg-webfont.eot differ diff --git a/public/fonts/embed/ColabReg-webfont.svg b/public/fonts/embed/ColabReg-webfont.svg new file mode 100644 index 0000000..92b650f --- /dev/null +++ b/public/fonts/embed/ColabReg-webfont.svg @@ -0,0 +1,142 @@ + + + + +This is a custom SVG webfont generated by Font Squirrel. +Foundry : This Font is designed by Ralph Oliver du Carrois + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/fonts/embed/ColabReg-webfont.ttf b/public/fonts/embed/ColabReg-webfont.ttf new file mode 100644 index 0000000..3bd22fa Binary files /dev/null and b/public/fonts/embed/ColabReg-webfont.ttf differ diff --git a/public/fonts/embed/ColabReg-webfont.woff b/public/fonts/embed/ColabReg-webfont.woff new file mode 100644 index 0000000..903e3a7 Binary files /dev/null and b/public/fonts/embed/ColabReg-webfont.woff differ diff --git a/public/fonts/embed/ColabThi-webfont.eot b/public/fonts/embed/ColabThi-webfont.eot new file mode 100644 index 0000000..f6c8de6 Binary files /dev/null and b/public/fonts/embed/ColabThi-webfont.eot differ diff --git a/public/fonts/embed/ColabThi-webfont.svg b/public/fonts/embed/ColabThi-webfont.svg new file mode 100644 index 0000000..334bc99 --- /dev/null +++ b/public/fonts/embed/ColabThi-webfont.svg @@ -0,0 +1,142 @@ + + + + +This is a custom SVG webfont generated by Font Squirrel. +Foundry : This Font is designed by Ralph Oliver du Carrois + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/fonts/embed/ColabThi-webfont.ttf b/public/fonts/embed/ColabThi-webfont.ttf new file mode 100644 index 0000000..8ec5ae1 Binary files /dev/null and b/public/fonts/embed/ColabThi-webfont.ttf differ diff --git a/public/fonts/embed/ColabThi-webfont.woff b/public/fonts/embed/ColabThi-webfont.woff new file mode 100644 index 0000000..d6ff334 Binary files /dev/null and b/public/fonts/embed/ColabThi-webfont.woff differ diff --git a/public/images/bidpacks/100-bids.jpg b/public/images/bidpacks/100-bids.jpg new file mode 100644 index 0000000..b5c359d Binary files /dev/null and b/public/images/bidpacks/100-bids.jpg differ diff --git a/public/images/bidpacks/200-bids.jpg b/public/images/bidpacks/200-bids.jpg new file mode 100644 index 0000000..b2be05b Binary files /dev/null and b/public/images/bidpacks/200-bids.jpg differ diff --git a/public/images/bidpacks/30-bids.jpg b/public/images/bidpacks/30-bids.jpg new file mode 100644 index 0000000..d33f11b Binary files /dev/null and b/public/images/bidpacks/30-bids.jpg differ diff --git a/public/images/bidpacks/50-bids.jpg b/public/images/bidpacks/50-bids.jpg new file mode 100644 index 0000000..058bc98 Binary files /dev/null and b/public/images/bidpacks/50-bids.jpg differ diff --git a/public/images/bidpacks/recommended-bid-pack.jpg b/public/images/bidpacks/recommended-bid-pack.jpg new file mode 100644 index 0000000..7431a71 Binary files /dev/null and b/public/images/bidpacks/recommended-bid-pack.jpg differ diff --git a/public/images/buttons/activate-account.gif b/public/images/buttons/activate-account.gif new file mode 100644 index 0000000..7197716 Binary files /dev/null and b/public/images/buttons/activate-account.gif differ diff --git a/public/images/buttons/activate-bid-assistant.gif b/public/images/buttons/activate-bid-assistant.gif new file mode 100644 index 0000000..162a9d0 Binary files /dev/null and b/public/images/buttons/activate-bid-assistant.gif differ diff --git a/public/images/buttons/add-item.gif b/public/images/buttons/add-item.gif new file mode 100644 index 0000000..6e3daa9 Binary files /dev/null and b/public/images/buttons/add-item.gif differ diff --git a/public/images/buttons/add-new-address.gif b/public/images/buttons/add-new-address.gif new file mode 100644 index 0000000..027068f Binary files /dev/null and b/public/images/buttons/add-new-address.gif differ diff --git a/public/images/buttons/add-to-watchlist.png b/public/images/buttons/add-to-watchlist.png new file mode 100644 index 0000000..1763606 Binary files /dev/null and b/public/images/buttons/add-to-watchlist.png differ diff --git a/public/images/buttons/admin-new-items.gif b/public/images/buttons/admin-new-items.gif new file mode 100644 index 0000000..787c79d Binary files /dev/null and b/public/images/buttons/admin-new-items.gif differ diff --git a/public/images/buttons/backarrow.png b/public/images/buttons/backarrow.png new file mode 100644 index 0000000..173f1a7 Binary files /dev/null and b/public/images/buttons/backarrow.png differ diff --git a/public/images/buttons/bid-large.gif b/public/images/buttons/bid-large.gif new file mode 100644 index 0000000..35f427c Binary files /dev/null and b/public/images/buttons/bid-large.gif differ diff --git a/public/images/buttons/bid-small.gif b/public/images/buttons/bid-small.gif new file mode 100644 index 0000000..e2de669 Binary files /dev/null and b/public/images/buttons/bid-small.gif differ diff --git a/public/images/buttons/bidding-tips.png b/public/images/buttons/bidding-tips.png new file mode 100644 index 0000000..6c8b659 Binary files /dev/null and b/public/images/buttons/bidding-tips.png differ diff --git a/public/images/buttons/buy-bids-small.png b/public/images/buttons/buy-bids-small.png new file mode 100644 index 0000000..4f601c9 Binary files /dev/null and b/public/images/buttons/buy-bids-small.png differ diff --git a/public/images/buttons/buy-now-narrow.gif b/public/images/buttons/buy-now-narrow.gif new file mode 100644 index 0000000..162b88d Binary files /dev/null and b/public/images/buttons/buy-now-narrow.gif differ diff --git a/public/images/buttons/buy-now-popup.png b/public/images/buttons/buy-now-popup.png new file mode 100644 index 0000000..8928528 Binary files /dev/null and b/public/images/buttons/buy-now-popup.png differ diff --git a/public/images/buttons/checkout.png b/public/images/buttons/checkout.png new file mode 100644 index 0000000..a348d47 Binary files /dev/null and b/public/images/buttons/checkout.png differ diff --git a/public/images/buttons/continue-shopping.png b/public/images/buttons/continue-shopping.png new file mode 100644 index 0000000..9403534 Binary files /dev/null and b/public/images/buttons/continue-shopping.png differ diff --git a/public/images/buttons/continue.png b/public/images/buttons/continue.png new file mode 100644 index 0000000..0856390 Binary files /dev/null and b/public/images/buttons/continue.png differ diff --git a/public/images/buttons/edit-item.png b/public/images/buttons/edit-item.png new file mode 100644 index 0000000..ccda197 Binary files /dev/null and b/public/images/buttons/edit-item.png differ diff --git a/public/images/buttons/edit.png b/public/images/buttons/edit.png new file mode 100644 index 0000000..ea069b9 Binary files /dev/null and b/public/images/buttons/edit.png differ diff --git a/public/images/buttons/editarrow.png b/public/images/buttons/editarrow.png new file mode 100644 index 0000000..2f014e2 Binary files /dev/null and b/public/images/buttons/editarrow.png differ diff --git a/public/images/buttons/feature-item.png b/public/images/buttons/feature-item.png new file mode 100644 index 0000000..7a37acd Binary files /dev/null and b/public/images/buttons/feature-item.png differ diff --git a/public/images/buttons/get-started.gif b/public/images/buttons/get-started.gif new file mode 100644 index 0000000..cffd5ff Binary files /dev/null and b/public/images/buttons/get-started.gif differ diff --git a/public/images/buttons/invite-friends-large.png b/public/images/buttons/invite-friends-large.png new file mode 100644 index 0000000..3aa6f09 Binary files /dev/null and b/public/images/buttons/invite-friends-large.png differ diff --git a/public/images/buttons/learn-more-large.png b/public/images/buttons/learn-more-large.png new file mode 100644 index 0000000..77d6b58 Binary files /dev/null and b/public/images/buttons/learn-more-large.png differ diff --git a/public/images/buttons/login-top.png b/public/images/buttons/login-top.png new file mode 100644 index 0000000..5e77d1a Binary files /dev/null and b/public/images/buttons/login-top.png differ diff --git a/public/images/buttons/login.png b/public/images/buttons/login.png new file mode 100644 index 0000000..44cc524 Binary files /dev/null and b/public/images/buttons/login.png differ diff --git a/public/images/buttons/order-now.png b/public/images/buttons/order-now.png new file mode 100644 index 0000000..0cd162a Binary files /dev/null and b/public/images/buttons/order-now.png differ diff --git a/public/images/buttons/paypal.png b/public/images/buttons/paypal.png new file mode 100644 index 0000000..9ef49b3 Binary files /dev/null and b/public/images/buttons/paypal.png differ diff --git a/public/images/buttons/pos-neg-admin-btn.png b/public/images/buttons/pos-neg-admin-btn.png new file mode 100644 index 0000000..d4c9533 Binary files /dev/null and b/public/images/buttons/pos-neg-admin-btn.png differ diff --git a/public/images/buttons/questionmark.gif b/public/images/buttons/questionmark.gif new file mode 100644 index 0000000..b9e1777 Binary files /dev/null and b/public/images/buttons/questionmark.gif differ diff --git a/public/images/buttons/redeem-coupon.png b/public/images/buttons/redeem-coupon.png new file mode 100644 index 0000000..0903066 Binary files /dev/null and b/public/images/buttons/redeem-coupon.png differ diff --git a/public/images/buttons/redeem-points.png b/public/images/buttons/redeem-points.png new file mode 100644 index 0000000..42823e5 Binary files /dev/null and b/public/images/buttons/redeem-points.png differ diff --git a/public/images/buttons/register-now.png b/public/images/buttons/register-now.png new file mode 100644 index 0000000..cbadd98 Binary files /dev/null and b/public/images/buttons/register-now.png differ diff --git a/public/images/buttons/reset-password.png b/public/images/buttons/reset-password.png new file mode 100644 index 0000000..97a94d4 Binary files /dev/null and b/public/images/buttons/reset-password.png differ diff --git a/public/images/buttons/save-address.gif b/public/images/buttons/save-address.gif new file mode 100644 index 0000000..26f7074 Binary files /dev/null and b/public/images/buttons/save-address.gif differ diff --git a/public/images/buttons/ship.gif b/public/images/buttons/ship.gif new file mode 100644 index 0000000..3b3e955 Binary files /dev/null and b/public/images/buttons/ship.gif differ diff --git a/public/images/buttons/showarrow.png b/public/images/buttons/showarrow.png new file mode 100644 index 0000000..5923913 Binary files /dev/null and b/public/images/buttons/showarrow.png differ diff --git a/public/images/buttons/site-rules.png b/public/images/buttons/site-rules.png new file mode 100644 index 0000000..151c566 Binary files /dev/null and b/public/images/buttons/site-rules.png differ diff --git a/public/images/buttons/splash-get-started.png b/public/images/buttons/splash-get-started.png new file mode 100644 index 0000000..0c622e2 Binary files /dev/null and b/public/images/buttons/splash-get-started.png differ diff --git a/public/images/buttons/start-bidding.png b/public/images/buttons/start-bidding.png new file mode 100644 index 0000000..7b08e57 Binary files /dev/null and b/public/images/buttons/start-bidding.png differ diff --git a/public/images/buttons/submit.png b/public/images/buttons/submit.png new file mode 100644 index 0000000..1f3cb3a Binary files /dev/null and b/public/images/buttons/submit.png differ diff --git a/public/images/buttons/viewonsite.png b/public/images/buttons/viewonsite.png new file mode 100644 index 0000000..4418803 Binary files /dev/null and b/public/images/buttons/viewonsite.png differ diff --git a/public/images/buttons/visit-facebook-button.png b/public/images/buttons/visit-facebook-button.png new file mode 100644 index 0000000..fd6f54a Binary files /dev/null and b/public/images/buttons/visit-facebook-button.png differ diff --git a/public/images/cc/discover.gif b/public/images/cc/discover.gif new file mode 100644 index 0000000..72e995a Binary files /dev/null and b/public/images/cc/discover.gif differ diff --git a/public/images/cc/mc.gif b/public/images/cc/mc.gif new file mode 100644 index 0000000..32b0d13 Binary files /dev/null and b/public/images/cc/mc.gif differ diff --git a/public/images/cc/visa-mc.gif b/public/images/cc/visa-mc.gif new file mode 100644 index 0000000..01ec2d8 Binary files /dev/null and b/public/images/cc/visa-mc.gif differ diff --git a/public/images/cc/visa.gif b/public/images/cc/visa.gif new file mode 100644 index 0000000..224cb62 Binary files /dev/null and b/public/images/cc/visa.gif differ diff --git a/public/images/email/body.gif b/public/images/email/body.gif new file mode 100644 index 0000000..db34492 Binary files /dev/null and b/public/images/email/body.gif differ diff --git a/public/images/email/footer-long.gif b/public/images/email/footer-long.gif new file mode 100644 index 0000000..1bab6f4 Binary files /dev/null and b/public/images/email/footer-long.gif differ diff --git a/public/images/email/footer.gif b/public/images/email/footer.gif new file mode 100644 index 0000000..415f55f Binary files /dev/null and b/public/images/email/footer.gif differ diff --git a/public/images/email/header.gif b/public/images/email/header.gif new file mode 100644 index 0000000..ea41ffc Binary files /dev/null and b/public/images/email/header.gif differ diff --git a/public/images/email/logo.gif b/public/images/email/logo.gif new file mode 100644 index 0000000..ea6959f Binary files /dev/null and b/public/images/email/logo.gif differ diff --git a/public/images/email/newsletters/030311/apple-day-banner.jpg b/public/images/email/newsletters/030311/apple-day-banner.jpg new file mode 100644 index 0000000..033681c Binary files /dev/null and b/public/images/email/newsletters/030311/apple-day-banner.jpg differ diff --git a/public/images/email/newsletters/030311/apple-day-banner.psd b/public/images/email/newsletters/030311/apple-day-banner.psd new file mode 100644 index 0000000..82649e8 Binary files /dev/null and b/public/images/email/newsletters/030311/apple-day-banner.psd differ diff --git a/public/images/email/newsletters/030311/apple-gc.jpg b/public/images/email/newsletters/030311/apple-gc.jpg new file mode 100644 index 0000000..1532d0b Binary files /dev/null and b/public/images/email/newsletters/030311/apple-gc.jpg differ diff --git a/public/images/email/newsletters/030311/apple-ipad.png b/public/images/email/newsletters/030311/apple-ipad.png new file mode 100644 index 0000000..8433ca5 Binary files /dev/null and b/public/images/email/newsletters/030311/apple-ipad.png differ diff --git a/public/images/email/newsletters/030311/apple-nano.png b/public/images/email/newsletters/030311/apple-nano.png new file mode 100644 index 0000000..551b311 Binary files /dev/null and b/public/images/email/newsletters/030311/apple-nano.png differ diff --git a/public/images/email/newsletters/030311/apple-shuffle.jpg b/public/images/email/newsletters/030311/apple-shuffle.jpg new file mode 100644 index 0000000..b606d7c Binary files /dev/null and b/public/images/email/newsletters/030311/apple-shuffle.jpg differ diff --git a/public/images/email/newsletters/030311/apple-touch.png b/public/images/email/newsletters/030311/apple-touch.png new file mode 100644 index 0000000..9c2f3a4 Binary files /dev/null and b/public/images/email/newsletters/030311/apple-touch.png differ diff --git a/public/images/email/newsletters/030311/apple-tv.jpg b/public/images/email/newsletters/030311/apple-tv.jpg new file mode 100644 index 0000000..b8677da Binary files /dev/null and b/public/images/email/newsletters/030311/apple-tv.jpg differ diff --git a/public/images/email/newsletters/030311/bid-now-oj-large.png b/public/images/email/newsletters/030311/bid-now-oj-large.png new file mode 100644 index 0000000..1fdf562 Binary files /dev/null and b/public/images/email/newsletters/030311/bid-now-oj-large.png differ diff --git a/public/images/email/newsletters/030311/bid-now-oj-large.psd b/public/images/email/newsletters/030311/bid-now-oj-large.psd new file mode 100644 index 0000000..19a4843 Binary files /dev/null and b/public/images/email/newsletters/030311/bid-now-oj-large.psd differ diff --git a/public/images/email/newsletters/030311/bot-wrap.png b/public/images/email/newsletters/030311/bot-wrap.png new file mode 100644 index 0000000..b4cf424 Binary files /dev/null and b/public/images/email/newsletters/030311/bot-wrap.png differ diff --git a/public/images/email/newsletters/030311/hp-g62.jpg b/public/images/email/newsletters/030311/hp-g62.jpg new file mode 100644 index 0000000..321aabe Binary files /dev/null and b/public/images/email/newsletters/030311/hp-g62.jpg differ diff --git a/public/images/email/newsletters/030311/hp-g62.psd b/public/images/email/newsletters/030311/hp-g62.psd new file mode 100644 index 0000000..c5cc2d9 Binary files /dev/null and b/public/images/email/newsletters/030311/hp-g62.psd differ diff --git a/public/images/email/newsletters/030311/logo.gif b/public/images/email/newsletters/030311/logo.gif new file mode 100644 index 0000000..4c47ae0 Binary files /dev/null and b/public/images/email/newsletters/030311/logo.gif differ diff --git a/public/images/email/newsletters/030311/logo.psd b/public/images/email/newsletters/030311/logo.psd new file mode 100644 index 0000000..979edbb Binary files /dev/null and b/public/images/email/newsletters/030311/logo.psd differ diff --git a/public/images/email/newsletters/030311/nav-bar.png b/public/images/email/newsletters/030311/nav-bar.png new file mode 100644 index 0000000..ec8e530 Binary files /dev/null and b/public/images/email/newsletters/030311/nav-bar.png differ diff --git a/public/images/email/newsletters/030311/nav-bar.psd b/public/images/email/newsletters/030311/nav-bar.psd new file mode 100644 index 0000000..9191a44 Binary files /dev/null and b/public/images/email/newsletters/030311/nav-bar.psd differ diff --git a/public/images/email/newsletters/030311/top-wrap.png b/public/images/email/newsletters/030311/top-wrap.png new file mode 100644 index 0000000..34398ff Binary files /dev/null and b/public/images/email/newsletters/030311/top-wrap.png differ diff --git a/public/images/email/signin.gif b/public/images/email/signin.gif new file mode 100644 index 0000000..5e43f8e Binary files /dev/null and b/public/images/email/signin.gif differ diff --git a/public/images/email/splices/body.jpg b/public/images/email/splices/body.jpg new file mode 100644 index 0000000..f8431fd Binary files /dev/null and b/public/images/email/splices/body.jpg differ diff --git a/public/images/email/splices/footer-short.jpg b/public/images/email/splices/footer-short.jpg new file mode 100644 index 0000000..29cee1c Binary files /dev/null and b/public/images/email/splices/footer-short.jpg differ diff --git a/public/images/email/splices/footer.jpg b/public/images/email/splices/footer.jpg new file mode 100644 index 0000000..17dd281 Binary files /dev/null and b/public/images/email/splices/footer.jpg differ diff --git a/public/images/email/splices/header.jpg b/public/images/email/splices/header.jpg new file mode 100644 index 0000000..e0b50f9 Binary files /dev/null and b/public/images/email/splices/header.jpg differ diff --git a/public/images/email/v030311/bot-wrap.png b/public/images/email/v030311/bot-wrap.png new file mode 100644 index 0000000..b4cf424 Binary files /dev/null and b/public/images/email/v030311/bot-wrap.png differ diff --git a/public/images/email/v030311/logo.gif b/public/images/email/v030311/logo.gif new file mode 100644 index 0000000..4c47ae0 Binary files /dev/null and b/public/images/email/v030311/logo.gif differ diff --git a/public/images/email/v030311/nav-bar.png b/public/images/email/v030311/nav-bar.png new file mode 100644 index 0000000..ec8e530 Binary files /dev/null and b/public/images/email/v030311/nav-bar.png differ diff --git a/public/images/email/v030311/top-wrap.png b/public/images/email/v030311/top-wrap.png new file mode 100644 index 0000000..34398ff Binary files /dev/null and b/public/images/email/v030311/top-wrap.png differ diff --git a/public/images/external/appconsumer/logo.gif b/public/images/external/appconsumer/logo.gif new file mode 100644 index 0000000..bd42dee Binary files /dev/null and b/public/images/external/appconsumer/logo.gif differ diff --git a/public/images/external/dailymakeover/logo.gif b/public/images/external/dailymakeover/logo.gif new file mode 100644 index 0000000..ad97637 Binary files /dev/null and b/public/images/external/dailymakeover/logo.gif differ diff --git a/public/images/external/powered-by.gif b/public/images/external/powered-by.gif new file mode 100644 index 0000000..bf71ca3 Binary files /dev/null and b/public/images/external/powered-by.gif differ diff --git a/public/images/facebook-fanpage/firstbargain/firstbargain-splash-v2.jpg b/public/images/facebook-fanpage/firstbargain/firstbargain-splash-v2.jpg new file mode 100644 index 0000000..c741fb9 Binary files /dev/null and b/public/images/facebook-fanpage/firstbargain/firstbargain-splash-v2.jpg differ diff --git a/public/images/facebook-fanpage/firstbargain/firstbargain-splash.jpg b/public/images/facebook-fanpage/firstbargain/firstbargain-splash.jpg new file mode 100644 index 0000000..a2c3968 Binary files /dev/null and b/public/images/facebook-fanpage/firstbargain/firstbargain-splash.jpg differ diff --git a/public/images/facebook-fanpage/firstbargain/how-to-play.jpg b/public/images/facebook-fanpage/firstbargain/how-to-play.jpg new file mode 100644 index 0000000..9b0f4c2 Binary files /dev/null and b/public/images/facebook-fanpage/firstbargain/how-to-play.jpg differ diff --git a/public/images/facebook-fanpage/firstbargain/how-to-text.gif b/public/images/facebook-fanpage/firstbargain/how-to-text.gif new file mode 100644 index 0000000..05ca0a7 Binary files /dev/null and b/public/images/facebook-fanpage/firstbargain/how-to-text.gif differ diff --git a/public/images/facebook-fanpage/firstbargain/like-us.jpg b/public/images/facebook-fanpage/firstbargain/like-us.jpg new file mode 100644 index 0000000..c94fbb1 Binary files /dev/null and b/public/images/facebook-fanpage/firstbargain/like-us.jpg differ diff --git a/public/images/facebook-fanpage/firstbargain/profile-image.jpg b/public/images/facebook-fanpage/firstbargain/profile-image.jpg new file mode 100644 index 0000000..47b2e71 Binary files /dev/null and b/public/images/facebook-fanpage/firstbargain/profile-image.jpg differ diff --git a/public/images/facebook-fanpage/firstbargain/registration-btn.png b/public/images/facebook-fanpage/firstbargain/registration-btn.png new file mode 100644 index 0000000..b90f076 Binary files /dev/null and b/public/images/facebook-fanpage/firstbargain/registration-btn.png differ diff --git a/public/images/facebook-fanpage/firstbargain/registration-text.gif b/public/images/facebook-fanpage/firstbargain/registration-text.gif new file mode 100644 index 0000000..1659cde Binary files /dev/null and b/public/images/facebook-fanpage/firstbargain/registration-text.gif differ diff --git a/public/images/facebook-fanpage/justhaute/main-splash.jpg b/public/images/facebook-fanpage/justhaute/main-splash.jpg new file mode 100644 index 0000000..e5a63b9 Binary files /dev/null and b/public/images/facebook-fanpage/justhaute/main-splash.jpg differ diff --git a/public/images/facebook-fanpage/justhaute/newpage-button.png b/public/images/facebook-fanpage/justhaute/newpage-button.png new file mode 100644 index 0000000..9b4627c Binary files /dev/null and b/public/images/facebook-fanpage/justhaute/newpage-button.png differ diff --git a/public/images/facebook-fanpage/justhaute/newpage-wrapper.jpg b/public/images/facebook-fanpage/justhaute/newpage-wrapper.jpg new file mode 100644 index 0000000..ecab1b8 Binary files /dev/null and b/public/images/facebook-fanpage/justhaute/newpage-wrapper.jpg differ diff --git a/public/images/facebook-fanpage/justhaute/recently-changed-url.png b/public/images/facebook-fanpage/justhaute/recently-changed-url.png new file mode 100644 index 0000000..e85b2a3 Binary files /dev/null and b/public/images/facebook-fanpage/justhaute/recently-changed-url.png differ diff --git a/public/images/faq/account.png b/public/images/faq/account.png new file mode 100644 index 0000000..0260e97 Binary files /dev/null and b/public/images/faq/account.png differ diff --git a/public/images/faq/auctions.png b/public/images/faq/auctions.png new file mode 100644 index 0000000..064190b Binary files /dev/null and b/public/images/faq/auctions.png differ diff --git a/public/images/faq/new-to-firstbargain.png b/public/images/faq/new-to-firstbargain.png new file mode 100644 index 0000000..01684ae Binary files /dev/null and b/public/images/faq/new-to-firstbargain.png differ diff --git a/public/images/faq/payment.png b/public/images/faq/payment.png new file mode 100644 index 0000000..cbc5a85 Binary files /dev/null and b/public/images/faq/payment.png differ diff --git a/public/images/faq/shipping.png b/public/images/faq/shipping.png new file mode 100644 index 0000000..0de0759 Binary files /dev/null and b/public/images/faq/shipping.png differ diff --git a/public/images/footer/mc.gif b/public/images/footer/mc.gif new file mode 100644 index 0000000..a2c58e3 Binary files /dev/null and b/public/images/footer/mc.gif differ diff --git a/public/images/footer/paypal.gif b/public/images/footer/paypal.gif new file mode 100644 index 0000000..ad89cf2 Binary files /dev/null and b/public/images/footer/paypal.gif differ diff --git a/public/images/footer/verisign.png b/public/images/footer/verisign.png new file mode 100644 index 0000000..75ca039 Binary files /dev/null and b/public/images/footer/verisign.png differ diff --git a/public/images/footer/visa.gif b/public/images/footer/visa.gif new file mode 100644 index 0000000..fa106c2 Binary files /dev/null and b/public/images/footer/visa.gif differ diff --git a/public/images/header/buy-bids-text.png b/public/images/header/buy-bids-text.png new file mode 100644 index 0000000..549a7e6 Binary files /dev/null and b/public/images/header/buy-bids-text.png differ diff --git a/public/images/header/facebook-link.png b/public/images/header/facebook-link.png new file mode 100644 index 0000000..952d3ce Binary files /dev/null and b/public/images/header/facebook-link.png differ diff --git a/public/images/header/firstbargain-how-to.jpg b/public/images/header/firstbargain-how-to.jpg new file mode 100644 index 0000000..2ac72d2 Binary files /dev/null and b/public/images/header/firstbargain-how-to.jpg differ diff --git a/public/images/header/get-started-text.png b/public/images/header/get-started-text.png new file mode 100644 index 0000000..e6e6a45 Binary files /dev/null and b/public/images/header/get-started-text.png differ diff --git a/public/images/header/invite-link.png b/public/images/header/invite-link.png new file mode 100644 index 0000000..45d5df6 Binary files /dev/null and b/public/images/header/invite-link.png differ diff --git a/public/images/header/logo.gif b/public/images/header/logo.gif new file mode 100644 index 0000000..d11ea4c Binary files /dev/null and b/public/images/header/logo.gif differ diff --git a/public/images/header/main-splash.jpg b/public/images/header/main-splash.jpg new file mode 100644 index 0000000..d963f22 Binary files /dev/null and b/public/images/header/main-splash.jpg differ diff --git a/public/images/header/nav-bg.png b/public/images/header/nav-bg.png new file mode 100644 index 0000000..2600161 Binary files /dev/null and b/public/images/header/nav-bg.png differ diff --git a/public/images/header/twitter.gif b/public/images/header/twitter.gif new file mode 100644 index 0000000..e36f6da Binary files /dev/null and b/public/images/header/twitter.gif differ diff --git a/public/images/how-to-play/apple-ipad.gif b/public/images/how-to-play/apple-ipad.gif new file mode 100644 index 0000000..929ce2a Binary files /dev/null and b/public/images/how-to-play/apple-ipad.gif differ diff --git a/public/images/how-to-play/bidding-tips.jpg b/public/images/how-to-play/bidding-tips.jpg new file mode 100644 index 0000000..342f29a Binary files /dev/null and b/public/images/how-to-play/bidding-tips.jpg differ diff --git a/public/images/how-to-play/buynow.gif b/public/images/how-to-play/buynow.gif new file mode 100644 index 0000000..5a945fc Binary files /dev/null and b/public/images/how-to-play/buynow.gif differ diff --git a/public/images/how-to-play/memberstore-cell.gif b/public/images/how-to-play/memberstore-cell.gif new file mode 100644 index 0000000..33771f4 Binary files /dev/null and b/public/images/how-to-play/memberstore-cell.gif differ diff --git a/public/images/how-to-play/shadow-top.png b/public/images/how-to-play/shadow-top.png new file mode 100644 index 0000000..fd44d2e Binary files /dev/null and b/public/images/how-to-play/shadow-top.png differ diff --git a/public/images/how-to-play/steps.jpg b/public/images/how-to-play/steps.jpg new file mode 100644 index 0000000..f4de2b3 Binary files /dev/null and b/public/images/how-to-play/steps.jpg differ diff --git a/public/images/how-to-play/tos-scroll.jpg b/public/images/how-to-play/tos-scroll.jpg new file mode 100644 index 0000000..2d94bc4 Binary files /dev/null and b/public/images/how-to-play/tos-scroll.jpg differ diff --git a/public/images/icons/bids-single.png b/public/images/icons/bids-single.png new file mode 100644 index 0000000..57f7743 Binary files /dev/null and b/public/images/icons/bids-single.png differ diff --git a/public/images/icons/buynow-trophy.png b/public/images/icons/buynow-trophy.png new file mode 100644 index 0000000..d07716a Binary files /dev/null and b/public/images/icons/buynow-trophy.png differ diff --git a/public/images/icons/connection.png b/public/images/icons/connection.png new file mode 100644 index 0000000..753674d Binary files /dev/null and b/public/images/icons/connection.png differ diff --git a/public/images/icons/discount-piggy.png b/public/images/icons/discount-piggy.png new file mode 100644 index 0000000..ddff1bf Binary files /dev/null and b/public/images/icons/discount-piggy.png differ diff --git a/public/images/icons/facebook.png b/public/images/icons/facebook.png new file mode 100644 index 0000000..8bf5971 Binary files /dev/null and b/public/images/icons/facebook.png differ diff --git a/public/images/icons/notepad.png b/public/images/icons/notepad.png new file mode 100644 index 0000000..1e3b97c Binary files /dev/null and b/public/images/icons/notepad.png differ diff --git a/public/images/icons/speaker.png b/public/images/icons/speaker.png new file mode 100644 index 0000000..c074c05 Binary files /dev/null and b/public/images/icons/speaker.png differ diff --git a/public/images/icons/star.png b/public/images/icons/star.png new file mode 100644 index 0000000..2f8c9f8 Binary files /dev/null and b/public/images/icons/star.png differ diff --git a/public/images/icons/support.png b/public/images/icons/support.png new file mode 100644 index 0000000..acb3f49 Binary files /dev/null and b/public/images/icons/support.png differ diff --git a/public/images/icons/trophy.png b/public/images/icons/trophy.png new file mode 100644 index 0000000..d567089 Binary files /dev/null and b/public/images/icons/trophy.png differ diff --git a/public/images/icons/us-dollar.png b/public/images/icons/us-dollar.png new file mode 100644 index 0000000..244e804 Binary files /dev/null and b/public/images/icons/us-dollar.png differ diff --git a/public/images/icons/user-order-history-legend.jpg b/public/images/icons/user-order-history-legend.jpg new file mode 100644 index 0000000..057a850 Binary files /dev/null and b/public/images/icons/user-order-history-legend.jpg differ diff --git a/public/images/icons/winner-trophy.png b/public/images/icons/winner-trophy.png new file mode 100644 index 0000000..bf6bc2a Binary files /dev/null and b/public/images/icons/winner-trophy.png differ diff --git a/public/images/jquery-ui-theme/ui-bg_diagonals-thick_18_b81900_40x40.png b/public/images/jquery-ui-theme/ui-bg_diagonals-thick_18_b81900_40x40.png new file mode 100755 index 0000000..954e22d Binary files /dev/null and b/public/images/jquery-ui-theme/ui-bg_diagonals-thick_18_b81900_40x40.png differ diff --git a/public/images/jquery-ui-theme/ui-bg_diagonals-thick_20_666666_40x40.png b/public/images/jquery-ui-theme/ui-bg_diagonals-thick_20_666666_40x40.png new file mode 100755 index 0000000..64ece57 Binary files /dev/null and b/public/images/jquery-ui-theme/ui-bg_diagonals-thick_20_666666_40x40.png differ diff --git a/public/images/jquery-ui-theme/ui-bg_flat_10_000000_40x100.png b/public/images/jquery-ui-theme/ui-bg_flat_10_000000_40x100.png new file mode 100755 index 0000000..abdc010 Binary files /dev/null and b/public/images/jquery-ui-theme/ui-bg_flat_10_000000_40x100.png differ diff --git a/public/images/jquery-ui-theme/ui-bg_glass_100_f6f6f6_1x400.png b/public/images/jquery-ui-theme/ui-bg_glass_100_f6f6f6_1x400.png new file mode 100755 index 0000000..9b383f4 Binary files /dev/null and b/public/images/jquery-ui-theme/ui-bg_glass_100_f6f6f6_1x400.png differ diff --git a/public/images/jquery-ui-theme/ui-bg_glass_100_fdf5ce_1x400.png b/public/images/jquery-ui-theme/ui-bg_glass_100_fdf5ce_1x400.png new file mode 100755 index 0000000..a23baad Binary files /dev/null and b/public/images/jquery-ui-theme/ui-bg_glass_100_fdf5ce_1x400.png differ diff --git a/public/images/jquery-ui-theme/ui-bg_glass_65_ffffff_1x400.png b/public/images/jquery-ui-theme/ui-bg_glass_65_ffffff_1x400.png new file mode 100755 index 0000000..42ccba2 Binary files /dev/null and b/public/images/jquery-ui-theme/ui-bg_glass_65_ffffff_1x400.png differ diff --git a/public/images/jquery-ui-theme/ui-bg_gloss-wave_35_f6a828_500x100.png b/public/images/jquery-ui-theme/ui-bg_gloss-wave_35_f6a828_500x100.png new file mode 100755 index 0000000..39d5824 Binary files /dev/null and b/public/images/jquery-ui-theme/ui-bg_gloss-wave_35_f6a828_500x100.png differ diff --git a/public/images/jquery-ui-theme/ui-bg_highlight-soft_100_eeeeee_1x100.png b/public/images/jquery-ui-theme/ui-bg_highlight-soft_100_eeeeee_1x100.png new file mode 100755 index 0000000..f127367 Binary files /dev/null and b/public/images/jquery-ui-theme/ui-bg_highlight-soft_100_eeeeee_1x100.png differ diff --git a/public/images/jquery-ui-theme/ui-bg_highlight-soft_75_ffe45c_1x100.png b/public/images/jquery-ui-theme/ui-bg_highlight-soft_75_ffe45c_1x100.png new file mode 100755 index 0000000..359397a Binary files /dev/null and b/public/images/jquery-ui-theme/ui-bg_highlight-soft_75_ffe45c_1x100.png differ diff --git a/public/images/jquery-ui-theme/ui-icons_222222_256x240.png b/public/images/jquery-ui-theme/ui-icons_222222_256x240.png new file mode 100755 index 0000000..b273ff1 Binary files /dev/null and b/public/images/jquery-ui-theme/ui-icons_222222_256x240.png differ diff --git a/public/images/jquery-ui-theme/ui-icons_228ef1_256x240.png b/public/images/jquery-ui-theme/ui-icons_228ef1_256x240.png new file mode 100755 index 0000000..a641a37 Binary files /dev/null and b/public/images/jquery-ui-theme/ui-icons_228ef1_256x240.png differ diff --git a/public/images/jquery-ui-theme/ui-icons_ef8c08_256x240.png b/public/images/jquery-ui-theme/ui-icons_ef8c08_256x240.png new file mode 100755 index 0000000..85e63e9 Binary files /dev/null and b/public/images/jquery-ui-theme/ui-icons_ef8c08_256x240.png differ diff --git a/public/images/jquery-ui-theme/ui-icons_ffd27a_256x240.png b/public/images/jquery-ui-theme/ui-icons_ffd27a_256x240.png new file mode 100755 index 0000000..e117eff Binary files /dev/null and b/public/images/jquery-ui-theme/ui-icons_ffd27a_256x240.png differ diff --git a/public/images/jquery-ui-theme/ui-icons_ffffff_256x240.png b/public/images/jquery-ui-theme/ui-icons_ffffff_256x240.png new file mode 100755 index 0000000..42f8f99 Binary files /dev/null and b/public/images/jquery-ui-theme/ui-icons_ffffff_256x240.png differ diff --git a/public/images/labels/bid-credits.png b/public/images/labels/bid-credits.png new file mode 100644 index 0000000..1528560 Binary files /dev/null and b/public/images/labels/bid-credits.png differ diff --git a/public/images/labels/bonus-credits.png b/public/images/labels/bonus-credits.png new file mode 100644 index 0000000..ca70a9b Binary files /dev/null and b/public/images/labels/bonus-credits.png differ diff --git a/public/images/labels/index-price-increment.png b/public/images/labels/index-price-increment.png new file mode 100644 index 0000000..c1b3e5a Binary files /dev/null and b/public/images/labels/index-price-increment.png differ diff --git a/public/images/labels/memberdiscount.gif b/public/images/labels/memberdiscount.gif new file mode 100644 index 0000000..589af71 Binary files /dev/null and b/public/images/labels/memberdiscount.gif differ diff --git a/public/images/labels/price-increment.png b/public/images/labels/price-increment.png new file mode 100644 index 0000000..8a98ace Binary files /dev/null and b/public/images/labels/price-increment.png differ diff --git a/public/images/labels/sale-tag.png b/public/images/labels/sale-tag.png new file mode 100644 index 0000000..e3c4780 Binary files /dev/null and b/public/images/labels/sale-tag.png differ diff --git a/public/images/labels/sold-overlay.png b/public/images/labels/sold-overlay.png new file mode 100644 index 0000000..59c7014 Binary files /dev/null and b/public/images/labels/sold-overlay.png differ diff --git a/public/images/labels/timer-increment.gif b/public/images/labels/timer-increment.gif new file mode 100644 index 0000000..f1fa1c8 Binary files /dev/null and b/public/images/labels/timer-increment.gif differ diff --git a/public/images/msc/ajax-loader.gif b/public/images/msc/ajax-loader.gif new file mode 100644 index 0000000..851866a Binary files /dev/null and b/public/images/msc/ajax-loader.gif differ diff --git a/public/images/msc/bid-unsuccessful.png b/public/images/msc/bid-unsuccessful.png new file mode 100644 index 0000000..f91fe59 Binary files /dev/null and b/public/images/msc/bid-unsuccessful.png differ diff --git a/public/images/msc/billing-separator.gif b/public/images/msc/billing-separator.gif new file mode 100644 index 0000000..cb6881f Binary files /dev/null and b/public/images/msc/billing-separator.gif differ diff --git a/public/images/msc/bullet.gif b/public/images/msc/bullet.gif new file mode 100644 index 0000000..d16eac9 Binary files /dev/null and b/public/images/msc/bullet.gif differ diff --git a/public/images/msc/close-icon.gif b/public/images/msc/close-icon.gif new file mode 100644 index 0000000..293ab2a Binary files /dev/null and b/public/images/msc/close-icon.gif differ diff --git a/public/images/msc/expanded-arrow.png b/public/images/msc/expanded-arrow.png new file mode 100644 index 0000000..ffda6fb Binary files /dev/null and b/public/images/msc/expanded-arrow.png differ diff --git a/public/images/msc/glasses-book.jpg b/public/images/msc/glasses-book.jpg new file mode 100644 index 0000000..1ec6f58 Binary files /dev/null and b/public/images/msc/glasses-book.jpg differ diff --git a/public/images/msc/login-arrow.png b/public/images/msc/login-arrow.png new file mode 100644 index 0000000..294e296 Binary files /dev/null and b/public/images/msc/login-arrow.png differ diff --git a/public/images/msc/logout-arrow.png b/public/images/msc/logout-arrow.png new file mode 100644 index 0000000..8b0b707 Binary files /dev/null and b/public/images/msc/logout-arrow.png differ diff --git a/public/images/msc/minus.gif b/public/images/msc/minus.gif new file mode 100644 index 0000000..95949fc Binary files /dev/null and b/public/images/msc/minus.gif differ diff --git a/public/images/msc/paypal-header.gif b/public/images/msc/paypal-header.gif new file mode 100644 index 0000000..c4489b9 Binary files /dev/null and b/public/images/msc/paypal-header.gif differ diff --git a/public/images/msc/plus.gif b/public/images/msc/plus.gif new file mode 100644 index 0000000..fbee7ad Binary files /dev/null and b/public/images/msc/plus.gif differ diff --git a/public/images/msc/satisfaction-guarantee.png b/public/images/msc/satisfaction-guarantee.png new file mode 100644 index 0000000..2046281 Binary files /dev/null and b/public/images/msc/satisfaction-guarantee.png differ diff --git a/public/images/msc/shipping-separator.gif b/public/images/msc/shipping-separator.gif new file mode 100644 index 0000000..94924cf Binary files /dev/null and b/public/images/msc/shipping-separator.gif differ diff --git a/public/images/msc/us-flag.gif b/public/images/msc/us-flag.gif new file mode 100644 index 0000000..ed74ba7 Binary files /dev/null and b/public/images/msc/us-flag.gif differ diff --git a/public/images/opacity/black-70.png b/public/images/opacity/black-70.png new file mode 100644 index 0000000..0b3ae32 Binary files /dev/null and b/public/images/opacity/black-70.png differ diff --git a/public/images/opacity/black-80.png b/public/images/opacity/black-80.png new file mode 100644 index 0000000..ffa133c Binary files /dev/null and b/public/images/opacity/black-80.png differ diff --git a/public/images/opacity/black-85.png b/public/images/opacity/black-85.png new file mode 100644 index 0000000..0c9c646 Binary files /dev/null and b/public/images/opacity/black-85.png differ diff --git a/public/images/promo/ended-auctions-text.png b/public/images/promo/ended-auctions-text.png new file mode 100644 index 0000000..9c1d240 Binary files /dev/null and b/public/images/promo/ended-auctions-text.png differ diff --git a/public/images/promo/ended-auctions.jpg b/public/images/promo/ended-auctions.jpg new file mode 100644 index 0000000..dfe783f Binary files /dev/null and b/public/images/promo/ended-auctions.jpg differ diff --git a/public/images/promo/firstbargain-savings.png b/public/images/promo/firstbargain-savings.png new file mode 100644 index 0000000..165357e Binary files /dev/null and b/public/images/promo/firstbargain-savings.png differ diff --git a/public/images/promo/firstbargain-vs-ebay.jpg b/public/images/promo/firstbargain-vs-ebay.jpg new file mode 100644 index 0000000..efc43f2 Binary files /dev/null and b/public/images/promo/firstbargain-vs-ebay.jpg differ diff --git a/public/images/promo/live-auctions-text.png b/public/images/promo/live-auctions-text.png new file mode 100644 index 0000000..6d131b9 Binary files /dev/null and b/public/images/promo/live-auctions-text.png differ diff --git a/public/images/promo/main-splash.jpg b/public/images/promo/main-splash.jpg new file mode 100644 index 0000000..33fabde Binary files /dev/null and b/public/images/promo/main-splash.jpg differ diff --git a/public/images/promo/ourprices.jpg b/public/images/promo/ourprices.jpg new file mode 100644 index 0000000..aed6beb Binary files /dev/null and b/public/images/promo/ourprices.jpg differ diff --git a/public/images/promo/penny-head-2.png b/public/images/promo/penny-head-2.png new file mode 100644 index 0000000..8472fef Binary files /dev/null and b/public/images/promo/penny-head-2.png differ diff --git a/public/images/promo/penny-head.jpg b/public/images/promo/penny-head.jpg new file mode 100644 index 0000000..8321c88 Binary files /dev/null and b/public/images/promo/penny-head.jpg differ diff --git a/public/images/promo/penny-quotes.jpg b/public/images/promo/penny-quotes.jpg new file mode 100644 index 0000000..e99a755 Binary files /dev/null and b/public/images/promo/penny-quotes.jpg differ diff --git a/public/images/promo/penny-revolution.jpg b/public/images/promo/penny-revolution.jpg new file mode 100644 index 0000000..dda1456 Binary files /dev/null and b/public/images/promo/penny-revolution.jpg differ diff --git a/public/images/promo/registration-heading.jpg b/public/images/promo/registration-heading.jpg new file mode 100644 index 0000000..6db1209 Binary files /dev/null and b/public/images/promo/registration-heading.jpg differ diff --git a/public/images/promo/savings-banner.jpg b/public/images/promo/savings-banner.jpg new file mode 100644 index 0000000..c6fdb37 Binary files /dev/null and b/public/images/promo/savings-banner.jpg differ diff --git a/public/images/promo/scroll-out.jpg b/public/images/promo/scroll-out.jpg new file mode 100644 index 0000000..a84e7da Binary files /dev/null and b/public/images/promo/scroll-out.jpg differ diff --git a/public/images/promo/signup-button.png b/public/images/promo/signup-button.png new file mode 100644 index 0000000..7a218f5 Binary files /dev/null and b/public/images/promo/signup-button.png differ diff --git a/public/images/promo/signup-short.png b/public/images/promo/signup-short.png new file mode 100644 index 0000000..38152a0 Binary files /dev/null and b/public/images/promo/signup-short.png differ diff --git a/public/images/promo/signup-wrap-01.jpg b/public/images/promo/signup-wrap-01.jpg new file mode 100644 index 0000000..5d04f34 Binary files /dev/null and b/public/images/promo/signup-wrap-01.jpg differ diff --git a/public/images/promo/signup-wrap-02.jpg b/public/images/promo/signup-wrap-02.jpg new file mode 100644 index 0000000..c57d656 Binary files /dev/null and b/public/images/promo/signup-wrap-02.jpg differ diff --git a/public/images/promo/signup-wrap-03.jpg b/public/images/promo/signup-wrap-03.jpg new file mode 100644 index 0000000..cdc3941 Binary files /dev/null and b/public/images/promo/signup-wrap-03.jpg differ diff --git a/public/images/promo/testimonials.jpg b/public/images/promo/testimonials.jpg new file mode 100644 index 0000000..6ff1cbc Binary files /dev/null and b/public/images/promo/testimonials.jpg differ diff --git a/public/images/promo/thousands-satisfied.jpg b/public/images/promo/thousands-satisfied.jpg new file mode 100644 index 0000000..ae48a5b Binary files /dev/null and b/public/images/promo/thousands-satisfied.jpg differ diff --git a/public/images/promo/welcome-heading.jpg b/public/images/promo/welcome-heading.jpg new file mode 100644 index 0000000..bad7e9a Binary files /dev/null and b/public/images/promo/welcome-heading.jpg differ diff --git a/public/images/promo/welcome-splash.jpg b/public/images/promo/welcome-splash.jpg new file mode 100644 index 0000000..21a1c30 Binary files /dev/null and b/public/images/promo/welcome-splash.jpg differ diff --git a/public/images/promo/winners-table.jpg b/public/images/promo/winners-table.jpg new file mode 100644 index 0000000..1a9b456 Binary files /dev/null and b/public/images/promo/winners-table.jpg differ diff --git a/public/images/server-status/maintenance.jpg b/public/images/server-status/maintenance.jpg new file mode 100644 index 0000000..d284986 Binary files /dev/null and b/public/images/server-status/maintenance.jpg differ diff --git a/public/images/slideshow/bargains.png b/public/images/slideshow/bargains.png new file mode 100644 index 0000000..6243b2d Binary files /dev/null and b/public/images/slideshow/bargains.png differ diff --git a/public/images/slideshow/facebook.png b/public/images/slideshow/facebook.png new file mode 100644 index 0000000..3e55d20 Binary files /dev/null and b/public/images/slideshow/facebook.png differ diff --git a/public/images/slideshow/featured/031311.png b/public/images/slideshow/featured/031311.png new file mode 100644 index 0000000..7d8c26d Binary files /dev/null and b/public/images/slideshow/featured/031311.png differ diff --git a/public/images/slideshow/featured/031611.png b/public/images/slideshow/featured/031611.png new file mode 100644 index 0000000..22fae48 Binary files /dev/null and b/public/images/slideshow/featured/031611.png differ diff --git a/public/images/slideshow/featured/032011.png b/public/images/slideshow/featured/032011.png new file mode 100644 index 0000000..4170e3a Binary files /dev/null and b/public/images/slideshow/featured/032011.png differ diff --git a/public/images/slideshow/featured/032311.png b/public/images/slideshow/featured/032311.png new file mode 100644 index 0000000..970aea2 Binary files /dev/null and b/public/images/slideshow/featured/032311.png differ diff --git a/public/images/slideshow/featured/032711.png b/public/images/slideshow/featured/032711.png new file mode 100644 index 0000000..d63d355 Binary files /dev/null and b/public/images/slideshow/featured/032711.png differ diff --git a/public/images/slideshow/featured/040311.png b/public/images/slideshow/featured/040311.png new file mode 100644 index 0000000..90daa50 Binary files /dev/null and b/public/images/slideshow/featured/040311.png differ diff --git a/public/images/slideshow/featured/040711.png b/public/images/slideshow/featured/040711.png new file mode 100644 index 0000000..c046e07 Binary files /dev/null and b/public/images/slideshow/featured/040711.png differ diff --git a/public/images/slideshow/how-to.png b/public/images/slideshow/how-to.png new file mode 100644 index 0000000..e3f3964 Binary files /dev/null and b/public/images/slideshow/how-to.png differ diff --git a/public/images/slideshow/nav-current-bg.png b/public/images/slideshow/nav-current-bg.png new file mode 100644 index 0000000..c737d53 Binary files /dev/null and b/public/images/slideshow/nav-current-bg.png differ diff --git a/public/images/slideshow/nav-first-current-bg.png b/public/images/slideshow/nav-first-current-bg.png new file mode 100644 index 0000000..c34d376 Binary files /dev/null and b/public/images/slideshow/nav-first-current-bg.png differ diff --git a/public/images/slideshow/promo-slideshow-bg.png b/public/images/slideshow/promo-slideshow-bg.png new file mode 100644 index 0000000..9db016c Binary files /dev/null and b/public/images/slideshow/promo-slideshow-bg.png differ diff --git a/public/images/slideshow/referral.png b/public/images/slideshow/referral.png new file mode 100644 index 0000000..4f5fd4c Binary files /dev/null and b/public/images/slideshow/referral.png differ diff --git a/public/images/slideshow/tips.png b/public/images/slideshow/tips.png new file mode 100644 index 0000000..bb0b454 Binary files /dev/null and b/public/images/slideshow/tips.png differ diff --git a/public/images/special-offers/apple-day/apple-day-banner.jpg b/public/images/special-offers/apple-day/apple-day-banner.jpg new file mode 100644 index 0000000..8abb0ee Binary files /dev/null and b/public/images/special-offers/apple-day/apple-day-banner.jpg differ diff --git a/public/images/special-offers/apple-day/visit-facebook-button.png b/public/images/special-offers/apple-day/visit-facebook-button.png new file mode 100644 index 0000000..fd6f54a Binary files /dev/null and b/public/images/special-offers/apple-day/visit-facebook-button.png differ diff --git a/public/images/special-offers/valentines-day/valentine.jpg b/public/images/special-offers/valentines-day/valentine.jpg new file mode 100644 index 0000000..82ec599 Binary files /dev/null and b/public/images/special-offers/valentines-day/valentine.jpg differ diff --git a/public/images/special-offers/valentines-day/visit-facebook-button.png b/public/images/special-offers/valentines-day/visit-facebook-button.png new file mode 100644 index 0000000..fd6f54a Binary files /dev/null and b/public/images/special-offers/valentines-day/visit-facebook-button.png differ diff --git a/public/images/text/about-us.gif b/public/images/text/about-us.gif new file mode 100644 index 0000000..17f1c13 Binary files /dev/null and b/public/images/text/about-us.gif differ diff --git a/public/images/text/activate-your-account.gif b/public/images/text/activate-your-account.gif new file mode 100644 index 0000000..e18b9a1 Binary files /dev/null and b/public/images/text/activate-your-account.gif differ diff --git a/public/images/text/affordable-prices.gif b/public/images/text/affordable-prices.gif new file mode 100644 index 0000000..7b2cc0a Binary files /dev/null and b/public/images/text/affordable-prices.gif differ diff --git a/public/images/text/authentic-guaranteed.gif b/public/images/text/authentic-guaranteed.gif new file mode 100644 index 0000000..18e88f3 Binary files /dev/null and b/public/images/text/authentic-guaranteed.gif differ diff --git a/public/images/text/bidding-tips.gif b/public/images/text/bidding-tips.gif new file mode 100644 index 0000000..88a4b50 Binary files /dev/null and b/public/images/text/bidding-tips.gif differ diff --git a/public/images/text/billing-address.png b/public/images/text/billing-address.png new file mode 100644 index 0000000..841e321 Binary files /dev/null and b/public/images/text/billing-address.png differ diff --git a/public/images/text/buy-bids.gif b/public/images/text/buy-bids.gif new file mode 100644 index 0000000..3386cd8 Binary files /dev/null and b/public/images/text/buy-bids.gif differ diff --git a/public/images/text/buynow-auctions.png b/public/images/text/buynow-auctions.png new file mode 100644 index 0000000..9136efb Binary files /dev/null and b/public/images/text/buynow-auctions.png differ diff --git a/public/images/text/cart/billing-address.gif b/public/images/text/cart/billing-address.gif new file mode 100644 index 0000000..5ef69d8 Binary files /dev/null and b/public/images/text/cart/billing-address.gif differ diff --git a/public/images/text/cart/payment-options.gif b/public/images/text/cart/payment-options.gif new file mode 100644 index 0000000..9d258c0 Binary files /dev/null and b/public/images/text/cart/payment-options.gif differ diff --git a/public/images/text/cart/shipping-address.gif b/public/images/text/cart/shipping-address.gif new file mode 100644 index 0000000..80a76f0 Binary files /dev/null and b/public/images/text/cart/shipping-address.gif differ diff --git a/public/images/text/confirm-order.gif b/public/images/text/confirm-order.gif new file mode 100644 index 0000000..b0f45f9 Binary files /dev/null and b/public/images/text/confirm-order.gif differ diff --git a/public/images/text/contact-us.gif b/public/images/text/contact-us.gif new file mode 100644 index 0000000..8bb8a9e Binary files /dev/null and b/public/images/text/contact-us.gif differ diff --git a/public/images/text/coveted-brands.gif b/public/images/text/coveted-brands.gif new file mode 100644 index 0000000..06e4936 Binary files /dev/null and b/public/images/text/coveted-brands.gif differ diff --git a/public/images/text/edit-account-information.png b/public/images/text/edit-account-information.png new file mode 100644 index 0000000..2399dcb Binary files /dev/null and b/public/images/text/edit-account-information.png differ diff --git a/public/images/text/ending-auctions.gif b/public/images/text/ending-auctions.gif new file mode 100644 index 0000000..40ded32 Binary files /dev/null and b/public/images/text/ending-auctions.gif differ diff --git a/public/images/text/faq.gif b/public/images/text/faq.gif new file mode 100644 index 0000000..7cef5ef Binary files /dev/null and b/public/images/text/faq.gif differ diff --git a/public/images/text/fb-guarantee.gif b/public/images/text/fb-guarantee.gif new file mode 100644 index 0000000..1665dd6 Binary files /dev/null and b/public/images/text/fb-guarantee.gif differ diff --git a/public/images/text/guarantee.gif b/public/images/text/guarantee.gif new file mode 100644 index 0000000..68f9f3c Binary files /dev/null and b/public/images/text/guarantee.gif differ diff --git a/public/images/text/how-to-play.gif b/public/images/text/how-to-play.gif new file mode 100644 index 0000000..7182fb0 Binary files /dev/null and b/public/images/text/how-to-play.gif differ diff --git a/public/images/text/invitations.png b/public/images/text/invitations.png new file mode 100644 index 0000000..afe45d1 Binary files /dev/null and b/public/images/text/invitations.png differ diff --git a/public/images/text/invite-explanation.gif b/public/images/text/invite-explanation.gif new file mode 100644 index 0000000..e4b8abf Binary files /dev/null and b/public/images/text/invite-explanation.gif differ diff --git a/public/images/text/invite-link-explanation.gif b/public/images/text/invite-link-explanation.gif new file mode 100644 index 0000000..ea858c0 Binary files /dev/null and b/public/images/text/invite-link-explanation.gif differ diff --git a/public/images/text/join-the-club.gif b/public/images/text/join-the-club.gif new file mode 100644 index 0000000..d65af27 Binary files /dev/null and b/public/images/text/join-the-club.gif differ diff --git a/public/images/text/member-rewards.gif b/public/images/text/member-rewards.gif new file mode 100644 index 0000000..ae7b389 Binary files /dev/null and b/public/images/text/member-rewards.gif differ diff --git a/public/images/text/members-discount.gif b/public/images/text/members-discount.gif new file mode 100644 index 0000000..5ca6d4e Binary files /dev/null and b/public/images/text/members-discount.gif differ diff --git a/public/images/text/members-shop.gif b/public/images/text/members-shop.gif new file mode 100644 index 0000000..09bbe29 Binary files /dev/null and b/public/images/text/members-shop.gif differ diff --git a/public/images/text/my-credits.png b/public/images/text/my-credits.png new file mode 100644 index 0000000..4afb794 Binary files /dev/null and b/public/images/text/my-credits.png differ diff --git a/public/images/text/my-shopping-cart.gif b/public/images/text/my-shopping-cart.gif new file mode 100644 index 0000000..fe97516 Binary files /dev/null and b/public/images/text/my-shopping-cart.gif differ diff --git a/public/images/text/my-wins.gif b/public/images/text/my-wins.gif new file mode 100644 index 0000000..75f84c2 Binary files /dev/null and b/public/images/text/my-wins.gif differ diff --git a/public/images/text/new-address.png b/public/images/text/new-address.png new file mode 100644 index 0000000..e0a235b Binary files /dev/null and b/public/images/text/new-address.png differ diff --git a/public/images/text/new-to-website.gif b/public/images/text/new-to-website.gif new file mode 100644 index 0000000..3119773 Binary files /dev/null and b/public/images/text/new-to-website.gif differ diff --git a/public/images/text/past-auction-winners.gif b/public/images/text/past-auction-winners.gif new file mode 100644 index 0000000..f95684a Binary files /dev/null and b/public/images/text/past-auction-winners.gif differ diff --git a/public/images/text/paypal.png b/public/images/text/paypal.png new file mode 100644 index 0000000..fe0f0e6 Binary files /dev/null and b/public/images/text/paypal.png differ diff --git a/public/images/text/privacy-policy.gif b/public/images/text/privacy-policy.gif new file mode 100644 index 0000000..8d23558 Binary files /dev/null and b/public/images/text/privacy-policy.gif differ diff --git a/public/images/text/product-description-learn-more.gif b/public/images/text/product-description-learn-more.gif new file mode 100644 index 0000000..8c2547f Binary files /dev/null and b/public/images/text/product-description-learn-more.gif differ diff --git a/public/images/text/product-description.gif b/public/images/text/product-description.gif new file mode 100644 index 0000000..18d1b49 Binary files /dev/null and b/public/images/text/product-description.gif differ diff --git a/public/images/text/redeem-auctions.png b/public/images/text/redeem-auctions.png new file mode 100644 index 0000000..f482ba3 Binary files /dev/null and b/public/images/text/redeem-auctions.png differ diff --git a/public/images/text/redeem-coupon-codes.png b/public/images/text/redeem-coupon-codes.png new file mode 100644 index 0000000..e08fd82 Binary files /dev/null and b/public/images/text/redeem-coupon-codes.png differ diff --git a/public/images/text/reset-your-password.gif b/public/images/text/reset-your-password.gif new file mode 100644 index 0000000..5d10391 Binary files /dev/null and b/public/images/text/reset-your-password.gif differ diff --git a/public/images/text/return-policy.gif b/public/images/text/return-policy.gif new file mode 100644 index 0000000..54f6300 Binary files /dev/null and b/public/images/text/return-policy.gif differ diff --git a/public/images/text/saved-addresses.png b/public/images/text/saved-addresses.png new file mode 100644 index 0000000..9ff20f6 Binary files /dev/null and b/public/images/text/saved-addresses.png differ diff --git a/public/images/text/share-this.png b/public/images/text/share-this.png new file mode 100644 index 0000000..09dd6ec Binary files /dev/null and b/public/images/text/share-this.png differ diff --git a/public/images/text/shipping-address.png b/public/images/text/shipping-address.png new file mode 100644 index 0000000..8d411c5 Binary files /dev/null and b/public/images/text/shipping-address.png differ diff --git a/public/images/text/sign-in-to-your-account.gif b/public/images/text/sign-in-to-your-account.gif new file mode 100644 index 0000000..6b45eb2 Binary files /dev/null and b/public/images/text/sign-in-to-your-account.gif differ diff --git a/public/images/text/site-rules.gif b/public/images/text/site-rules.gif new file mode 100644 index 0000000..af20ff1 Binary files /dev/null and b/public/images/text/site-rules.gif differ diff --git a/public/images/text/terms-of-service.gif b/public/images/text/terms-of-service.gif new file mode 100644 index 0000000..46bc14b Binary files /dev/null and b/public/images/text/terms-of-service.gif differ diff --git a/public/images/text/thank-you.gif b/public/images/text/thank-you.gif new file mode 100644 index 0000000..f47a774 Binary files /dev/null and b/public/images/text/thank-you.gif differ diff --git a/public/images/text/upcoming-auctions.gif b/public/images/text/upcoming-auctions.gif new file mode 100644 index 0000000..39452c9 Binary files /dev/null and b/public/images/text/upcoming-auctions.gif differ diff --git a/public/images/text/watchlist.png b/public/images/text/watchlist.png new file mode 100644 index 0000000..9c66eda Binary files /dev/null and b/public/images/text/watchlist.png differ diff --git a/public/images/text/were-sorry.gif b/public/images/text/were-sorry.gif new file mode 100644 index 0000000..85cfecd Binary files /dev/null and b/public/images/text/were-sorry.gif differ diff --git a/public/images/text/your-order-history.png b/public/images/text/your-order-history.png new file mode 100644 index 0000000..637e13c Binary files /dev/null and b/public/images/text/your-order-history.png differ diff --git a/public/images/viewer/20_opacity_black.png b/public/images/viewer/20_opacity_black.png new file mode 100644 index 0000000..c58fb60 Binary files /dev/null and b/public/images/viewer/20_opacity_black.png differ diff --git a/public/images/viewer/20_opacity_white.png b/public/images/viewer/20_opacity_white.png new file mode 100644 index 0000000..8c5f794 Binary files /dev/null and b/public/images/viewer/20_opacity_white.png differ diff --git a/public/images/viewer/50_opacity_black.png b/public/images/viewer/50_opacity_black.png new file mode 100644 index 0000000..807ac5d Binary files /dev/null and b/public/images/viewer/50_opacity_black.png differ diff --git a/public/images/viewer/75_opacity_black.png b/public/images/viewer/75_opacity_black.png new file mode 100644 index 0000000..dff76ea Binary files /dev/null and b/public/images/viewer/75_opacity_black.png differ diff --git a/public/images/viewer/8_opacity_white.png b/public/images/viewer/8_opacity_white.png new file mode 100644 index 0000000..23b1a12 Binary files /dev/null and b/public/images/viewer/8_opacity_white.png differ diff --git a/public/images/viewer/bg.jpg b/public/images/viewer/bg.jpg new file mode 100644 index 0000000..664c587 Binary files /dev/null and b/public/images/viewer/bg.jpg differ diff --git a/public/images/viewer/footer_bg.png b/public/images/viewer/footer_bg.png new file mode 100644 index 0000000..138d823 Binary files /dev/null and b/public/images/viewer/footer_bg.png differ diff --git a/public/images/viewer/logo.png b/public/images/viewer/logo.png new file mode 100644 index 0000000..d910b57 Binary files /dev/null and b/public/images/viewer/logo.png differ diff --git a/public/images/viewer/submit_btn.png b/public/images/viewer/submit_btn.png new file mode 100644 index 0000000..9a11352 Binary files /dev/null and b/public/images/viewer/submit_btn.png differ diff --git a/public/images/wrapper/about-tabs/advisory-bg.png b/public/images/wrapper/about-tabs/advisory-bg.png new file mode 100644 index 0000000..4125557 Binary files /dev/null and b/public/images/wrapper/about-tabs/advisory-bg.png differ diff --git a/public/images/wrapper/about-tabs/bg.png b/public/images/wrapper/about-tabs/bg.png new file mode 100644 index 0000000..b664205 Binary files /dev/null and b/public/images/wrapper/about-tabs/bg.png differ diff --git a/public/images/wrapper/about-tabs/overview-bg.png b/public/images/wrapper/about-tabs/overview-bg.png new file mode 100644 index 0000000..0bdc22f Binary files /dev/null and b/public/images/wrapper/about-tabs/overview-bg.png differ diff --git a/public/images/wrapper/about-tabs/team-bg.png b/public/images/wrapper/about-tabs/team-bg.png new file mode 100644 index 0000000..84865ec Binary files /dev/null and b/public/images/wrapper/about-tabs/team-bg.png differ diff --git a/public/images/wrapper/beginner-auction-popup.png b/public/images/wrapper/beginner-auction-popup.png new file mode 100644 index 0000000..7eb403f Binary files /dev/null and b/public/images/wrapper/beginner-auction-popup.png differ diff --git a/public/images/wrapper/beginner-auction.png b/public/images/wrapper/beginner-auction.png new file mode 100644 index 0000000..a534d4f Binary files /dev/null and b/public/images/wrapper/beginner-auction.png differ diff --git a/public/images/wrapper/dashboard-main-menu-bg.png b/public/images/wrapper/dashboard-main-menu-bg.png new file mode 100644 index 0000000..d63d851 Binary files /dev/null and b/public/images/wrapper/dashboard-main-menu-bg.png differ diff --git a/public/images/wrapper/dashboard-nav-arrow.png b/public/images/wrapper/dashboard-nav-arrow.png new file mode 100644 index 0000000..dec72d7 Binary files /dev/null and b/public/images/wrapper/dashboard-nav-arrow.png differ diff --git a/public/images/wrapper/featured-auction.png b/public/images/wrapper/featured-auction.png new file mode 100644 index 0000000..f8be572 Binary files /dev/null and b/public/images/wrapper/featured-auction.png differ diff --git a/public/images/wrapper/footer-wrapper.png b/public/images/wrapper/footer-wrapper.png new file mode 100644 index 0000000..0458a49 Binary files /dev/null and b/public/images/wrapper/footer-wrapper.png differ diff --git a/public/images/wrapper/hot-auction.png b/public/images/wrapper/hot-auction.png new file mode 100644 index 0000000..34e557e Binary files /dev/null and b/public/images/wrapper/hot-auction.png differ diff --git a/public/images/wrapper/how-to-tabs/auctions.gif b/public/images/wrapper/how-to-tabs/auctions.gif new file mode 100644 index 0000000..4e0d97b Binary files /dev/null and b/public/images/wrapper/how-to-tabs/auctions.gif differ diff --git a/public/images/wrapper/how-to-tabs/bg.png b/public/images/wrapper/how-to-tabs/bg.png new file mode 100644 index 0000000..b664205 Binary files /dev/null and b/public/images/wrapper/how-to-tabs/bg.png differ diff --git a/public/images/wrapper/how-to-tabs/guarantee.gif b/public/images/wrapper/how-to-tabs/guarantee.gif new file mode 100644 index 0000000..399dbf5 Binary files /dev/null and b/public/images/wrapper/how-to-tabs/guarantee.gif differ diff --git a/public/images/wrapper/how-to-tabs/rewards.gif b/public/images/wrapper/how-to-tabs/rewards.gif new file mode 100644 index 0000000..8c022c5 Binary files /dev/null and b/public/images/wrapper/how-to-tabs/rewards.gif differ diff --git a/public/images/wrapper/invites-tabs/bg.png b/public/images/wrapper/invites-tabs/bg.png new file mode 100644 index 0000000..b664205 Binary files /dev/null and b/public/images/wrapper/invites-tabs/bg.png differ diff --git a/public/images/wrapper/invites-tabs/invite-friends.png b/public/images/wrapper/invites-tabs/invite-friends.png new file mode 100644 index 0000000..7e1a379 Binary files /dev/null and b/public/images/wrapper/invites-tabs/invite-friends.png differ diff --git a/public/images/wrapper/invites-tabs/your-invites.png b/public/images/wrapper/invites-tabs/your-invites.png new file mode 100644 index 0000000..dce1801 Binary files /dev/null and b/public/images/wrapper/invites-tabs/your-invites.png differ diff --git a/public/images/wrapper/main-wrapper.png b/public/images/wrapper/main-wrapper.png new file mode 100644 index 0000000..597a52f Binary files /dev/null and b/public/images/wrapper/main-wrapper.png differ diff --git a/public/images/wrapper/my-wins-wrapper.gif b/public/images/wrapper/my-wins-wrapper.gif new file mode 100644 index 0000000..82d346a Binary files /dev/null and b/public/images/wrapper/my-wins-wrapper.gif differ diff --git a/public/images/wrapper/new-bidder-popup.png b/public/images/wrapper/new-bidder-popup.png new file mode 100644 index 0000000..1d570d0 Binary files /dev/null and b/public/images/wrapper/new-bidder-popup.png differ diff --git a/public/images/wrapper/payment-tabs/bg.png b/public/images/wrapper/payment-tabs/bg.png new file mode 100644 index 0000000..b664205 Binary files /dev/null and b/public/images/wrapper/payment-tabs/bg.png differ diff --git a/public/images/wrapper/payment-tabs/cc-bg.png b/public/images/wrapper/payment-tabs/cc-bg.png new file mode 100644 index 0000000..1064dfd Binary files /dev/null and b/public/images/wrapper/payment-tabs/cc-bg.png differ diff --git a/public/images/wrapper/payment-tabs/pp-bg.png b/public/images/wrapper/payment-tabs/pp-bg.png new file mode 100644 index 0000000..5993933 Binary files /dev/null and b/public/images/wrapper/payment-tabs/pp-bg.png differ diff --git a/public/images/wrapper/product-cell.png b/public/images/wrapper/product-cell.png new file mode 100644 index 0000000..2213030 Binary files /dev/null and b/public/images/wrapper/product-cell.png differ diff --git a/public/images/wrapper/shadow-right.png b/public/images/wrapper/shadow-right.png new file mode 100644 index 0000000..8f6f366 Binary files /dev/null and b/public/images/wrapper/shadow-right.png differ diff --git a/public/javascripts/application.js b/public/javascripts/application.js new file mode 100644 index 0000000..224b856 --- /dev/null +++ b/public/javascripts/application.js @@ -0,0 +1,209 @@ +/*! + * Copyright 2010 Expedient Shopping, Inc. + * Not to be copied or distributed without the written consent of Expedient Shopping, Inc. + */ +var rollOvers = {}; +var small_bid_complete = '0 -120px'; +var large_bid_complete = '0 -150px'; +var A = {}; // All auctions on page. + +/* Product image rollovers */ +function registerRollover(elem, img) { + rollOvers[elem] = img; +} + +function auctionDialog (_title, body) { + $("#error-modal-dialog").text(body).dialog({ title: _title }).dialog('open'); + return false; +} + +$(function() { + // Internal variables + var mouse_is_inside = false; + var small_bidding = '0 -40px'; + var large_bidding = '0 -50px'; + var toDisable = '#shipping-address-toggle-node, #order_billing_address, #order_billing_address_2, #order_billing_city, #order_billing_state, #order_billing_zip, #order_billing_phone, #order_shipping_name, #order_shipping_address, #order_shipping_address_2, #order_shipping_city, #order_shipping_state, #order_shipping_zip, #order_shipping_phone'; + var latency = [0,0,0,0]; + var cur_l = 0; + var start_t = 0; + var $connStatus = $("#user-credits-main .latency"); + var connText = ""; + function updateConnStatus() { + var avg_lat = (latency[0]+latency[1]+latency[2]+latency[3])/4; + if(avg_lat < 300) { + $connStatus.attr("class","latency conn-good"); + if(connText !== "good") { + $connStatus.unbind("hover"); + connText = "good"; + $connStatus.tipTip({content: "Your internet connection is good"}); + } + } else if(avg_lat < 700) { + $connStatus.attr("class","latency conn-fair"); + if(connText !== "fair") { + $connStatus.unbind("hover"); + connText = "fair"; + $connStatus.tipTip({content: "Your internet connection is fair"}); + } + } else { + $connStatus.attr("class","latency conn-poor"); + if(connText !== "poor") { + $connStatus.unbind("hover"); + connText = "poor"; + $connStatus.tipTip({content: "Your internet connection is poor"}); + } + } + } + $("body").ajaxSend(function (event, xhr, options) { + start_t = new Date(); + }); + $("body").ajaxSuccess(function (event, xhr, options) { + latency[(cur_l++)%4] = new Date().getTime() - start_t.getTime(); + updateConnStatus(); + }); + $("body").ajaxError(function (event, xhr, options, thrownError) { + latency[(cur_l++)%4] = 2400; + updateConnStatus(); + if (xhr.status == 503) { // System disruption + window.location = "system/maintenance.html" + } + }); + + // Hides and Removes "checked" property for Shipping Address checkbox -- Fix browser caching form inputs + //$('#checkout-address #shipping-address').hide(); + $('#checkout-address #shipping-address-toggle-node').attr('checked', false); + $(toDisable).attr('disabled', false); + + // Shipping Address Toggling + $('#checkout-address #shipping-address-toggle-node').click(function () { + $('#checkout-address #shipping-address').slideToggle('slow'); + }); + + // Top Login Form Toggling + $('#top-login #toggle-node').click(function(e){ + e.preventDefault(); + $('#top-login #login-body').toggle(); + $('#top-login #toggle-node').toggleClass('expanded'); + }); + $('#top-login #login-body').mouseup(function(){ + return false; + }); + $(document).mouseup(function(e){ + if($(e.target).parent('#top-login #toggle-node').length==0){ + $('#top-login #toggle-node').removeClass('expanded'); + $('#top-login #login-body').hide(); + } + }); + + // IMAGE GALLERY + $("#gallery li").mouseenter(function () { + $('#viewer img').attr("src", rollOvers[$(this).attr('id')]); + }); + + // Payment Selection + $('#cc-tab').click(function () { + $(this).addClass('selected'); + $('#pp-tab').removeClass('selected'); + $('#credit-card-form').stop(true, true).show(); + $('#paypal-form').stop(true, true).hide(); + $(toDisable).attr('disabled', false); + $("#order_gateway").val("authorize"); + }); + $('#pp-tab').click(function () { + $(this).addClass('selected'); + $('#cc-tab').removeClass('selected'); + $('#paypal-form').stop(true, true).show(); + $('#credit-card-form').stop(true, true).hide(); + $(toDisable).attr('disabled', 'disabled'); + $('#order_gateway').val("paypal"); + }); + + // Binds AJAX bid clicks + $('#main-auctions form, #watchlist-auctions form').bind("ajax:before", function () { + A[parseInt(this.id, 10)].bidding = true; + $(this.commit).css('background-position', small_bidding).attr('disabled', 'disabled'); + }); + $('#main-numbers form').bind("ajax:before", function () { + A[parseInt(this.id, 10)].bidding = true; + $(this.commit).css('background-position', large_bidding).attr('disabled', 'disabled'); + }); + + // Invitation Page Tabs + $('#invite-friends-tab').click(function () { + $(this).addClass('selected'); + $('#your-invites-tab').removeClass('selected'); + $('#invite-friends').stop(true, true).show(); + $('#your-invites').stop(true, true).hide(); + }); + $('#your-invites-tab').click(function () { + $(this).addClass('selected'); + $('#invite-friends-tab').removeClass('selected'); + $('#your-invites').stop(true, true).show(); + $('#invite-friends').stop(true, true).hide(); + }); + + // FAQ toggle + $(".faq-block h3").click(function() { + var block = $(this).parent(); + if (block.hasClass("faq-hidden")) { + block.removeClass("faq-hidden"); + } else { + block.addClass("faq-hidden"); + } + }); + // FAQ Hover Effects + $("#faq-page-index .column").hover(function() { + var button = $(this).children(":first"); + button.addClass("revealed"); + }, + function () { + var button = $(this).children(":first"); + button.removeClass("revealed"); + }); + + // POP UPS + $('a.popup').live('click', function(){ + newwindow = window.open($(this).attr('href'),'','height=400,width=600,scrollbars=yes,left=200,top=50'); + if (window.focus) { newwindow.focus(); } + return false; + }); + + // BUY NOW AND ERROR CLOSE + $('.overlay-popup-toggle').click(function() { + $(this).parent().hide(); + }); + + // tipTip trigger + $(".hasTooltip").tipTip({maxWidth: "270px"}); + + // Orders History Table Toggle + $("#show-void-declined").click(function() { + var wrap = $(this).parent(); + var tab = wrap.children(":first"); + if (tab.hasClass("order-history-hidden")) { + tab.removeClass("order-history-hidden"); + $(this).text("Hide Void & Declined Orders"); + } else { + tab.addClass("order-history-hidden"); + $(this).text("Show Void & Declined Orders"); + } + }); + + // Order confirmation screen + $("#place-order form").bind("ajax:before", function () { + $("#place-order").hide(); + $("#order-processing").show(); + }); + + // Initialize Modal Dialogs + $("#error-modal-dialog").dialog({ + width: 400, + draggable: false, + closeOnEscape: true, + dialogClass: 'error-modal-dialog', + autoOpen: false, + resizable: false, + modal: true, + buttons:{ "Close": function() { $(this).dialog('close'); } } + }); + +}); // closes doc ready function \ No newline at end of file diff --git a/public/javascripts/jquery.js b/public/javascripts/jquery.js new file mode 100644 index 0000000..b2ac174 --- /dev/null +++ b/public/javascripts/jquery.js @@ -0,0 +1,18 @@ +/*! + * jQuery JavaScript Library v1.6.1 + * http://jquery.com/ + * + * Copyright 2011, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Thu May 12 15:04:36 2011 -0400 + */ +(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!cj[a]){var b=f("<"+a+">").appendTo("body"),d=b.css("display");b.remove();if(d==="none"||d===""){ck||(ck=c.createElement("iframe"),ck.frameBorder=ck.width=ck.height=0),c.body.appendChild(ck);if(!cl||!ck.createElement)cl=(ck.contentWindow||ck.contentDocument).document,cl.write("");b=cl.createElement(a),cl.body.appendChild(b),d=f.css(b,"display"),c.body.removeChild(ck)}cj[a]=d}return cj[a]}function cu(a,b){var c={};f.each(cp.concat.apply([],cp.slice(0,b)),function(){c[this]=a});return c}function ct(){cq=b}function cs(){setTimeout(ct,0);return cq=f.now()}function ci(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ch(){try{return new a.XMLHttpRequest}catch(b){}}function cb(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g=0===c})}function W(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function O(a,b){return(a&&a!=="*"?a+".":"")+b.replace(A,"`").replace(B,"&")}function N(a){var b,c,d,e,g,h,i,j,k,l,m,n,o,p=[],q=[],r=f._data(this,"events");if(!(a.liveFired===this||!r||!r.live||a.target.disabled||a.button&&a.type==="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var s=r.live.slice(0);for(i=0;ic)break;a.currentTarget=e.elem,a.data=e.handleObj.data,a.handleObj=e.handleObj,o=e.handleObj.origHandler.apply(e.elem,arguments);if(o===!1||a.isPropagationStopped()){c=e.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function L(a,c,d){var e=f.extend({},d[0]);e.type=a,e.originalEvent={},e.liveFired=b,f.event.handle.call(c,e),e.isDefaultPrevented()&&d[0].preventDefault()}function F(){return!0}function E(){return!1}function m(a,c,d){var e=c+"defer",g=c+"queue",h=c+"mark",i=f.data(a,e,b,!0);i&&(d==="queue"||!f.data(a,g,b,!0))&&(d==="mark"||!f.data(a,h,b,!0))&&setTimeout(function(){!f.data(a,g,b,!0)&&!f.data(a,h,b,!0)&&(f.removeData(a,e,!0),i.resolve())},0)}function l(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function k(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(j,"$1-$2").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNaN(d)?i.test(d)?f.parseJSON(d):d:parseFloat(d)}catch(g){}f.data(a,c,d)}else d=b}return d}var c=a.document,d=a.navigator,e=a.location,f=function(){function H(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(H,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=d.userAgent,x,y,z,A=Object.prototype.toString,B=Object.prototype.hasOwnProperty,C=Array.prototype.push,D=Array.prototype.slice,E=String.prototype.trim,F=Array.prototype.indexOf,G={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.6.1",length:0,size:function(){return this.length},toArray:function(){return D.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?C.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),y.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(D.apply(this,arguments),"slice",D.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:C,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;y.resolveWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!y){y=e._Deferred();if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",z,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",z),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&H()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNaN:function(a){return a==null||!m.test(a)||isNaN(a)},type:function(a){return a==null?String(a):G[A.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;if(a.constructor&&!B.call(a,"constructor")&&!B.call(a.constructor.prototype,"isPrototypeOf"))return!1;var c;for(c in a);return c===b||B.call(a,c)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(b,c,d){a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b)),d=c.documentElement,(!d||!d.nodeName||d.nodeName==="parsererror")&&e.error("Invalid XML: "+b);return c},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?h.call(arguments,0):c,--e||g.resolveWith(g,h.call(b,0))}}var b=arguments,c=0,d=b.length,e=d,g=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred();if(d>1){for(;c
a",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};f=c.createElement("select"),g=f.appendChild(c.createElement("option")),h=a.getElementsByTagName("input")[0],j={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55$/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:h.value==="on",optSelected:g.selected,getSetAttribute:a.className!=="t",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},h.checked=!0,j.noCloneChecked=h.cloneNode(!0).checked,f.disabled=!0,j.optDisabled=!g.disabled;try{delete a.test}catch(s){j.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function b(){j.noCloneEvent=!1,a.detachEvent("onclick",b)}),a.cloneNode(!0).fireEvent("onclick")),h=c.createElement("input"),h.value="t",h.setAttribute("type","radio"),j.radioValue=h.value==="t",h.setAttribute("checked","checked"),a.appendChild(h),k=c.createDocumentFragment(),k.appendChild(a.firstChild),j.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",l=c.createElement("body"),m={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"};for(q in m)l.style[q]=m[q];l.appendChild(a),b.insertBefore(l,b.firstChild),j.appendChecked=h.checked,j.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,j.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="
",j.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="
t
",n=a.getElementsByTagName("td"),r=n[0].offsetHeight===0,n[0].style.display="",n[1].style.display="none",j.reliableHiddenOffsets=r&&n[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(i=c.createElement("div"),i.style.width="0",i.style.marginRight="0",a.appendChild(i),j.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(i,null)||{marginRight:0}).marginRight,10)||0)===0),l.innerHTML="",b.removeChild(l);if(a.attachEvent)for(q in{submit:1,change:1,focusin:1})p="on"+q,r=p in a,r||(a.setAttribute(p,"return;"),r=typeof a[p]=="function"),j[q+"Bubbles"]=r;return j}(),f.boxModel=f.support.boxModel;var i=/^(?:\{.*\}|\[.*\])$/,j=/([a-z])([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!l(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g=f.expando,h=typeof c=="string",i,j=a.nodeType,k=j?f.cache:a,l=j?a[f.expando]:a[f.expando]&&f.expando;if((!l||e&&l&&!k[l][g])&&h&&d===b)return;l||(j?a[f.expando]=l=++f.uuid:l=f.expando),k[l]||(k[l]={},j||(k[l].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?k[l][g]=f.extend(k[l][g],c):k[l]=f.extend(k[l],c);i=k[l],e&&(i[g]||(i[g]={}),i=i[g]),d!==b&&(i[f.camelCase(c)]=d);if(c==="events"&&!i[c])return i[g]&&i[g].events;return h?i[f.camelCase(c)]:i}},removeData:function(b,c,d){if(!!f.acceptData(b)){var e=f.expando,g=b.nodeType,h=g?f.cache:b,i=g?b[f.expando]:f.expando;if(!h[i])return;if(c){var j=d?h[i][e]:h[i];if(j){delete j[c];if(!l(j))return}}if(d){delete h[i][e];if(!l(h[i]))return}var k=h[i][e];f.support.deleteExpando||h!=a?delete h[i]:h[i]=null,k?(h[i]={},g||(h[i].toJSON=f.noop),h[i][e]=k):g&&(f.support.deleteExpando?delete b[f.expando]:b.removeAttribute?b.removeAttribute(f.expando):b[f.expando]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d=null;if(typeof a=="undefined"){if(this.length){d=f.data(this[0]);if(this[0].nodeType===1){var e=this[0].attributes,g;for(var h=0,i=e.length;h-1)return!0;return!1},val:function(a){var c,d,e=this[0];if(!arguments.length){if(e){c=f.valHooks[e.nodeName.toLowerCase()]||f.valHooks[e.type];if(c&&"get"in c&&(d=c.get(e,"value"))!==b)return d;return(e.value||"").replace(p,"")}return b}var g=f.isFunction(a);return this.each(function(d){var e=f(this),h;if(this.nodeType===1){g?h=a.call(this,d,e.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c=a.selectedIndex,d=[],e=a.options,g=a.type==="select-one";if(c<0)return null;for(var h=g?c:0,i=g?c+1:e.length;h=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attrFix:{tabindex:"tabIndex"},attr:function(a,c,d,e){var g=a.nodeType;if(!a||g===3||g===8||g===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!("getAttribute"in a))return f.prop(a,c,d);var h,i,j=g!==1||!f.isXMLDoc(a);c=j&&f.attrFix[c]||c,i=f.attrHooks[c],i||(!t.test(c)||typeof d!="boolean"&&d!==b&&d.toLowerCase()!==c.toLowerCase()?v&&(f.nodeName(a,"form")||u.test(c))&&(i=v):i=w);if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(i&&"set"in i&&j&&(h=i.set(a,d,c))!==b)return h;a.setAttribute(c,""+d);return d}if(i&&"get"in i&&j)return i.get(a,c);h=a.getAttribute(c);return h===null?b:h},removeAttr:function(a,b){var c;a.nodeType===1&&(b=f.attrFix[b]||b,f.support.getSetAttribute?a.removeAttribute(b):(f.attr(a,b,""),a.removeAttributeNode(a.getAttributeNode(b))),t.test(b)&&(c=f.propFix[b]||b)in a&&(a[c]=!1))},attrHooks:{type:{set:function(a,b){if(q.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},tabIndex:{get:function(a){var c=a.getAttributeNode("tabIndex");return c&&c.specified?parseInt(c.value,10):r.test(a.nodeName)||s.test(a.nodeName)&&a.href?0:b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e=a.nodeType;if(!a||e===3||e===8||e===2)return b;var g,h,i=e!==1||!f.isXMLDoc(a);c=i&&f.propFix[c]||c,h=f.propHooks[c];return d!==b?h&&"set"in h&&(g=h.set(a,d,c))!==b?g:a[c]=d:h&&"get"in h&&(g=h.get(a,c))!==b?g:a[c]},propHooks:{}}),w={get:function(a,c){return a[f.propFix[c]||c]?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=b),a.setAttribute(c,c.toLowerCase()));return c}},f.attrHooks.value={get:function(a,b){if(v&&f.nodeName(a,"button"))return v.get(a,b);return a.value},set:function(a,b,c){if(v&&f.nodeName(a,"button"))return v.set(a,b,c);a.value=b}},f.support.getSetAttribute||(f.attrFix=f.propFix,v=f.attrHooks.name=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&d.nodeValue!==""?d.nodeValue:b},set:function(a,b,c){var d=a.getAttributeNode(c);if(d){d.nodeValue=b;return b}}},f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})})),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}})),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var x=Object.prototype.hasOwnProperty,y=/\.(.*)$/,z=/^(?:textarea|input|select)$/i,A=/\./g,B=/ /g,C=/[^\w\s.|`]/g,D=function(a){return a.replace(C,"\\$&")};f.event={add:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){if(d===!1)d=E;else if(!d)return;var g,h;d.handler&&(g=d,d=g.handler),d.guid||(d.guid=f.guid++);var i=f._data(a);if(!i)return;var j=i.events,k=i.handle;j||(i.events=j={}),k||(i.handle=k=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.handle.apply(k.elem,arguments):b}),k.elem=a,c=c.split(" ");var l,m=0,n;while(l=c[m++]){h=g?f.extend({},g):{handler:d,data:e},l.indexOf(".")>-1?(n=l.split("."),l=n.shift(),h.namespace=n.slice(0).sort().join(".")):(n=[],h.namespace=""),h.type=l,h.guid||(h.guid=d.guid);var o=j[l],p=f.event.special[l]||{};if(!o){o=j[l]=[];if(!p.setup||p.setup.call(a,e,n,k)===!1)a.addEventListener?a.addEventListener(l,k,!1):a.attachEvent&&a.attachEvent("on"+l,k)}p.add&&(p.add.call(a,h),h.handler.guid||(h.handler.guid=d.guid)),o.push(h),f.event.global[l]=!0}a=null}},global:{},remove:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){d===!1&&(d=E);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=f.hasData(a)&&f._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(d=c.handler,c=c.type);if(!c||typeof c=="string"&&c.charAt(0)==="."){c=c||"";for(h in t)f.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+f.map(m.slice(0).sort(),D).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!d){for(j=0;j=0&&(h=h.slice(0,-1),j=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if(!!e&&!f.event.customEvent[h]||!!f.event.global[h]){c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.exclusive=j,c.namespace=i.join("."),c.namespace_re=new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)");if(g||!e)c.preventDefault(),c.stopPropagation();if(!e){f.each(f.cache,function(){var a=f.expando,b=this[a];b&&b.events&&b.events[h]&&f.event.trigger(c,d,b.handle.elem +)});return}if(e.nodeType===3||e.nodeType===8)return;c.result=b,c.target=e,d=d?f.makeArray(d):[],d.unshift(c);var k=e,l=h.indexOf(":")<0?"on"+h:"";do{var m=f._data(k,"handle");c.currentTarget=k,m&&m.apply(k,d),l&&f.acceptData(k)&&k[l]&&k[l].apply(k,d)===!1&&(c.result=!1,c.preventDefault()),k=k.parentNode||k.ownerDocument||k===c.target.ownerDocument&&a}while(k&&!c.isPropagationStopped());if(!c.isDefaultPrevented()){var n,o=f.event.special[h]||{};if((!o._default||o._default.call(e.ownerDocument,c)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)){try{l&&e[h]&&(n=e[l],n&&(e[l]=null),f.event.triggered=h,e[h]())}catch(p){}n&&(e[l]=n),f.event.triggered=b}}return c.result}},handle:function(c){c=f.event.fix(c||a.event);var d=((f._data(this,"events")||{})[c.type]||[]).slice(0),e=!c.exclusive&&!c.namespace,g=Array.prototype.slice.call(arguments,0);g[0]=c,c.currentTarget=this;for(var h=0,i=d.length;h-1?f.map(a.options,function(a){return a.selected}).join("-"):"":f.nodeName(a,"select")&&(c=a.selectedIndex);return c},K=function(c){var d=c.target,e,g;if(!!z.test(d.nodeName)&&!d.readOnly){e=f._data(d,"_change_data"),g=J(d),(c.type!=="focusout"||d.type!=="radio")&&f._data(d,"_change_data",g);if(e===b||g===e)return;if(e!=null||g)c.type="change",c.liveFired=b,f.event.trigger(c,arguments[1],d)}};f.event.special.change={filters:{focusout:K,beforedeactivate:K,click:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(c==="radio"||c==="checkbox"||f.nodeName(b,"select"))&&K.call(this,a)},keydown:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(a.keyCode===13&&!f.nodeName(b,"textarea")||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&K.call(this,a)},beforeactivate:function(a){var b=a.target;f._data(b,"_change_data",J(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in I)f.event.add(this,c+".specialChange",I[c]);return z.test(this.nodeName)},teardown:function(a){f.event.remove(this,".specialChange");return z.test(this.nodeName)}},I=f.event.special.change.filters,I.focus=I.beforeactivate}f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){function e(a){var c=f.event.fix(a);c.type=b,c.originalEvent={},f.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var d=0;f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.each(["bind","one"],function(a,c){f.fn[c]=function(a,d,e){var g;if(typeof a=="object"){for(var h in a)this[c](h,d,a[h],e);return this}if(arguments.length===2||d===!1)e=d,d=b;c==="one"?(g=function(a){f(this).unbind(a,g);return e.apply(this,arguments)},g.guid=e.guid||f.guid++):g=e;if(a==="unload"&&c!=="one")this.one(a,d,e);else for(var i=0,j=this.length;i0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d=0,e=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,f,g){f=f||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return f;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(e.call(n)==="[object Array]")if(!u)f.push.apply(f,n);else if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&f.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&f.push(j[t]);else p(n,f);o&&(k(o,h,f,g),k.uniqueSort(f));return f};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=d++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(e.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var f=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g0)for(h=g;h0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(d=0,e=a.length;d-1:f(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=U.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a||typeof a=="string")return f.inArray(this[0],a?f(a):this.parent().children());return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(W(c[0])||W(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c),g=T.call(arguments);P.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!V[a]?f.unique(e):e,(this.length>1||R.test(d))&&Q.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var Y=/ jQuery\d+="(?:\d+|null)"/g,Z=/^\s+/,$=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,_=/<([\w:]+)/,ba=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div
","
"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Y,""):null;if(typeof a=="string"&&!bc.test(a)&&(f.support.leadingWhitespace||!Z.test(a))&&!bg[(_.exec(a)||["",""])[1].toLowerCase()]){a=a.replace($,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bj(a,d),e=bk(a),g=bk(d);for(h=0;e[h];++h)bj(e[h],g[h])}if(b){bi(a,d);if(c){e=bk(a),g=bk(d);for(h=0;e[h];++h)bi(e[h],g[h])}}return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument|| +b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!bb.test(k))k=b.createTextNode(k);else{k=k.replace($,"<$1>");var l=(_.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=ba.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&Z.test(k)&&o.insertBefore(b.createTextNode(Z.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bp.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle;c.zoom=1;var e=f.isNaN(b)?"":"alpha(opacity="+b*100+")",g=d&&d.filter||c.filter||"";c.filter=bo.test(g)?g.replace(bo,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,c){var d,e,g;c=c.replace(br,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bs.test(d)&&bt.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bE=/%20/g,bF=/\[\]$/,bG=/\r?\n/g,bH=/#.*$/,bI=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bJ=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bK=/^(?:about|app|app\-storage|.+\-extension|file|widget):$/,bL=/^(?:GET|HEAD)$/,bM=/^\/\//,bN=/\?/,bO=/)<[^<]*)*<\/script>/gi,bP=/^(?:select|textarea)/i,bQ=/\s+/,bR=/([?&])_=[^&]*/,bS=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bT=f.fn.load,bU={},bV={},bW,bX;try{bW=e.href}catch(bY){bW=c.createElement("a"),bW.href="",bW=bW.href}bX=bS.exec(bW.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bT)return bT.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
").append(c.replace(bO,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bP.test(this.nodeName)||bJ.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bG,"\r\n")}}):{name:b.name,value:c.replace(bG,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.bind(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?f.extend(!0,a,f.ajaxSettings,b):(b=a,a=f.extend(!0,f.ajaxSettings,b));for(var c in{context:1,url:1})c in b?a[c]=b[c]:c in f.ajaxSettings&&(a[c]=f.ajaxSettings[c]);return a},ajaxSettings:{url:bW,isLocal:bK.test(bX[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":"*/*"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML}},ajaxPrefilter:bZ(bU),ajaxTransport:bZ(bV),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a?4:0;var o,r,u,w=l?ca(d,v,l):b,x,y;if(a>=200&&a<300||a===304){if(d.ifModified){if(x=v.getResponseHeader("Last-Modified"))f.lastModified[k]=x;if(y=v.getResponseHeader("Etag"))f.etag[k]=y}if(a===304)c="notmodified",o=!0;else try{r=cb(d,w),c="success",o=!0}catch(z){c="parsererror",u=z}}else{u=c;if(!c||a)c="error",a<0&&(a=0)}v.status=a,v.statusText=c,o?h.resolveWith(e,[r,c,v]):h.rejectWith(e,[v,c,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.resolveWith(e,[v,c]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f._Deferred(),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bI.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.done,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bH,"").replace(bM,bX[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bQ),d.crossDomain==null&&(r=bS.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bX[1]&&r[2]==bX[2]&&(r[3]||(r[1]==="http:"?80:443))==(bX[3]||(bX[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bU,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bL.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bN.test(d.url)?"&":"?")+d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bR,"$1_="+x);d.url=y+(y===d.url?(bN.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", */*; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bV,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){status<2?w(-1,z):f.error(z)}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)b_(g,a[g],c,e);return d.join("&").replace(bE,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cc=f.now(),cd=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cc++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(cd.test(b.url)||e&&cd.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(cd,l),b.url===j&&(e&&(k=k.replace(cd,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var ce=a.ActiveXObject?function(){for(var a in cg)cg[a](0,1)}:!1,cf=0,cg;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ch()||ci()}:ch,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,ce&&delete cg[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cf,ce&&(cg||(cg={},f(a).unload(ce)),cg[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cj={},ck,cl,cm=/^(?:toggle|show|hide)$/,cn=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,co,cp=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cq,cr=a.webkitRequestAnimationFrame||a.mozRequestAnimationFrame||a.oRequestAnimationFrame;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g=e.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),e.animatedProperties[this.prop]=!0;for(g in e.animatedProperties)e.animatedProperties[g]!==!0&&(c=!1);if(c){e.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){d.style["overflow"+b]=e.overflow[a]}),e.hide&&f(d).hide();if(e.hide||e.show)for(var i in e.animatedProperties)f.style(d,i,e.orig[i]);e.complete.call(d)}return!1}e.duration==Infinity?this.now=b:(h=b-this.startTime,this.state=h/e.duration,this.pos=f.easing[e.animatedProperties[this.prop]](this.state,h,0,1,e.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){for(var a=f.timers,b=0;b
";f.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),d=b.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,this.doesNotAddBorder=e.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,e.style.position="fixed",e.style.top="20px",this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),f.offset.initialize=f.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.offset.initialize(),f.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){return this[0]?parseFloat(f.css(this[0],d,"padding")):null},f.fn["outer"+c]=function(a){return this[0]?parseFloat(f.css(this[0],d,a?"margin":"border")):null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c];return e.document.compatMode==="CSS1Compat"&&g||e.document.body["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var h=f.css(e,d),i=parseFloat(h);return f.isNaN(i)?h:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f})(window); \ No newline at end of file diff --git a/public/javascripts/jqueryui.js b/public/javascripts/jqueryui.js new file mode 100755 index 0000000..9c610bc --- /dev/null +++ b/public/javascripts/jqueryui.js @@ -0,0 +1,401 @@ +/*! + * jQuery UI 1.8.6 + * + * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI + */ +(function(b,c){function f(g){return!b(g).parents().andSelf().filter(function(){return b.curCSS(this,"visibility")==="hidden"||b.expr.filters.hidden(this)}).length}b.ui=b.ui||{};if(!b.ui.version){b.extend(b.ui,{version:"1.8.6",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106, +NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});b.fn.extend({_focus:b.fn.focus,focus:function(g,e){return typeof g==="number"?this.each(function(){var a=this;setTimeout(function(){b(a).focus();e&&e.call(a)},g)}):this._focus.apply(this,arguments)},scrollParent:function(){var g;g=b.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(b.curCSS(this, +"position",1))&&/(auto|scroll)/.test(b.curCSS(this,"overflow",1)+b.curCSS(this,"overflow-y",1)+b.curCSS(this,"overflow-x",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(b.curCSS(this,"overflow",1)+b.curCSS(this,"overflow-y",1)+b.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!g.length?b(document):g},zIndex:function(g){if(g!==c)return this.css("zIndex",g);if(this.length){g=b(this[0]);for(var e;g.length&&g[0]!==document;){e=g.css("position"); +if(e==="absolute"||e==="relative"||e==="fixed"){e=parseInt(g.css("zIndex"),10);if(!isNaN(e)&&e!==0)return e}g=g.parent()}}return 0},disableSelection:function(){return this.bind((b.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(g){g.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});b.each(["Width","Height"],function(g,e){function a(j,n,q,l){b.each(d,function(){n-=parseFloat(b.curCSS(j,"padding"+this,true))||0;if(q)n-=parseFloat(b.curCSS(j, +"border"+this+"Width",true))||0;if(l)n-=parseFloat(b.curCSS(j,"margin"+this,true))||0});return n}var d=e==="Width"?["Left","Right"]:["Top","Bottom"],h=e.toLowerCase(),i={innerWidth:b.fn.innerWidth,innerHeight:b.fn.innerHeight,outerWidth:b.fn.outerWidth,outerHeight:b.fn.outerHeight};b.fn["inner"+e]=function(j){if(j===c)return i["inner"+e].call(this);return this.each(function(){b(this).css(h,a(this,j)+"px")})};b.fn["outer"+e]=function(j,n){if(typeof j!=="number")return i["outer"+e].call(this,j);return this.each(function(){b(this).css(h, +a(this,j,true,n)+"px")})}});b.extend(b.expr[":"],{data:function(g,e,a){return!!b.data(g,a[3])},focusable:function(g){var e=g.nodeName.toLowerCase(),a=b.attr(g,"tabindex");if("area"===e){e=g.parentNode;a=e.name;if(!g.href||!a||e.nodeName.toLowerCase()!=="map")return false;g=b("img[usemap=#"+a+"]")[0];return!!g&&f(g)}return(/input|select|textarea|button|object/.test(e)?!g.disabled:"a"==e?g.href||!isNaN(a):!isNaN(a))&&f(g)},tabbable:function(g){var e=b.attr(g,"tabindex");return(isNaN(e)||e>=0)&&b(g).is(":focusable")}}); +b(function(){var g=document.body,e=g.appendChild(e=document.createElement("div"));b.extend(e.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});b.support.minHeight=e.offsetHeight===100;b.support.selectstart="onselectstart"in e;g.removeChild(e).style.display="none"});b.extend(b.ui,{plugin:{add:function(g,e,a){g=b.ui[g].prototype;for(var d in a){g.plugins[d]=g.plugins[d]||[];g.plugins[d].push([e,a[d]])}},call:function(g,e,a){if((e=g.plugins[e])&&g.element[0].parentNode)for(var d=0;d0)return true;g[e]=1;a=g[e]>0;g[e]=0;return a},isOverAxis:function(g,e,a){return g>e&&g=9)&&!c.button)return this._mouseUp(c);if(this._mouseStarted){this._mouseDrag(c);return c.preventDefault()}if(this._mouseDistanceMet(c)&& +this._mouseDelayMet(c))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,c)!==false)?this._mouseDrag(c):this._mouseUp(c);return!this._mouseStarted},_mouseUp:function(c){b(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;this._preventClickEvent=c.target==this._mouseDownEvent.target;this._mouseStop(c)}return false},_mouseDistanceMet:function(c){return Math.max(Math.abs(this._mouseDownEvent.pageX- +c.pageX),Math.abs(this._mouseDownEvent.pageY-c.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery); +(function(b){b.widget("ui.draggable",b.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:true,appendTo:"parent",axis:false,connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false},_create:function(){if(this.options.helper== +"original"&&!/^(?:r|a|f)/.test(this.element.css("position")))this.element[0].style.position="relative";this.options.addClasses&&this.element.addClass("ui-draggable");this.options.disabled&&this.element.addClass("ui-draggable-disabled");this._mouseInit()},destroy:function(){if(this.element.data("draggable")){this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy();return this}},_mouseCapture:function(c){var f= +this.options;if(this.helper||f.disabled||b(c.target).is(".ui-resizable-handle"))return false;this.handle=this._getHandle(c);if(!this.handle)return false;return true},_mouseStart:function(c){var f=this.options;this.helper=this._createHelper(c);this._cacheHelperProportions();if(b.ui.ddmanager)b.ui.ddmanager.current=this;this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.positionAbs=this.element.offset();this.offset={top:this.offset.top- +this.margins.top,left:this.offset.left-this.margins.left};b.extend(this.offset,{click:{left:c.pageX-this.offset.left,top:c.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this.position=this._generatePosition(c);this.originalPageX=c.pageX;this.originalPageY=c.pageY;f.cursorAt&&this._adjustOffsetFromHelper(f.cursorAt);f.containment&&this._setContainment();if(this._trigger("start",c)===false){this._clear();return false}this._cacheHelperProportions(); +b.ui.ddmanager&&!f.dropBehaviour&&b.ui.ddmanager.prepareOffsets(this,c);this.helper.addClass("ui-draggable-dragging");this._mouseDrag(c,true);return true},_mouseDrag:function(c,f){this.position=this._generatePosition(c);this.positionAbs=this._convertPositionTo("absolute");if(!f){f=this._uiHash();if(this._trigger("drag",c,f)===false){this._mouseUp({});return false}this.position=f.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis|| +this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";b.ui.ddmanager&&b.ui.ddmanager.drag(this,c);return false},_mouseStop:function(c){var f=false;if(b.ui.ddmanager&&!this.options.dropBehaviour)f=b.ui.ddmanager.drop(this,c);if(this.dropped){f=this.dropped;this.dropped=false}if(!this.element[0]||!this.element[0].parentNode)return false;if(this.options.revert=="invalid"&&!f||this.options.revert=="valid"&&f||this.options.revert===true||b.isFunction(this.options.revert)&&this.options.revert.call(this.element, +f)){var g=this;b(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){g._trigger("stop",c)!==false&&g._clear()})}else this._trigger("stop",c)!==false&&this._clear();return false},cancel:function(){this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear();return this},_getHandle:function(c){var f=!this.options.handle||!b(this.options.handle,this.element).length?true:false;b(this.options.handle,this.element).find("*").andSelf().each(function(){if(this== +c.target)f=true});return f},_createHelper:function(c){var f=this.options;c=b.isFunction(f.helper)?b(f.helper.apply(this.element[0],[c])):f.helper=="clone"?this.element.clone():this.element;c.parents("body").length||c.appendTo(f.appendTo=="parent"?this.element[0].parentNode:f.appendTo);c[0]!=this.element[0]&&!/(fixed|absolute)/.test(c.css("position"))&&c.css("position","absolute");return c},_adjustOffsetFromHelper:function(c){if(typeof c=="string")c=c.split(" ");if(b.isArray(c))c={left:+c[0],top:+c[1]|| +0};if("left"in c)this.offset.click.left=c.left+this.margins.left;if("right"in c)this.offset.click.left=this.helperProportions.width-c.right+this.margins.left;if("top"in c)this.offset.click.top=c.top+this.margins.top;if("bottom"in c)this.offset.click.top=this.helperProportions.height-c.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var c=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&b.ui.contains(this.scrollParent[0], +this.offsetParent[0])){c.left+=this.scrollParent.scrollLeft();c.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&b.browser.msie)c={top:0,left:0};return{top:c.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:c.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var c=this.element.position();return{top:c.top- +(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:c.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var c=this.options;if(c.containment== +"parent")c.containment=this.helper[0].parentNode;if(c.containment=="document"||c.containment=="window")this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,b(c.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(b(c.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(c.containment)&& +c.containment.constructor!=Array){var f=b(c.containment)[0];if(f){c=b(c.containment).offset();var g=b(f).css("overflow")!="hidden";this.containment=[c.left+(parseInt(b(f).css("borderLeftWidth"),10)||0)+(parseInt(b(f).css("paddingLeft"),10)||0)-this.margins.left,c.top+(parseInt(b(f).css("borderTopWidth"),10)||0)+(parseInt(b(f).css("paddingTop"),10)||0)-this.margins.top,c.left+(g?Math.max(f.scrollWidth,f.offsetWidth):f.offsetWidth)-(parseInt(b(f).css("borderLeftWidth"),10)||0)-(parseInt(b(f).css("paddingRight"), +10)||0)-this.helperProportions.width-this.margins.left,c.top+(g?Math.max(f.scrollHeight,f.offsetHeight):f.offsetHeight)-(parseInt(b(f).css("borderTopWidth"),10)||0)-(parseInt(b(f).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}}else if(c.containment.constructor==Array)this.containment=c.containment},_convertPositionTo:function(c,f){if(!f)f=this.position;c=c=="absolute"?1:-1;var g=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&b.ui.contains(this.scrollParent[0], +this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(g[0].tagName);return{top:f.top+this.offset.relative.top*c+this.offset.parent.top*c-(b.browser.safari&&b.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:g.scrollTop())*c),left:f.left+this.offset.relative.left*c+this.offset.parent.left*c-(b.browser.safari&&b.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft(): +e?0:g.scrollLeft())*c)}},_generatePosition:function(c){var f=this.options,g=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&b.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(g[0].tagName),a=c.pageX,d=c.pageY;if(this.originalPosition){if(this.containment){if(c.pageX-this.offset.click.leftthis.containment[2])a=this.containment[2]+this.offset.click.left;if(c.pageY-this.offset.click.top>this.containment[3])d=this.containment[3]+this.offset.click.top}if(f.grid){d=this.originalPageY+Math.round((d-this.originalPageY)/f.grid[1])*f.grid[1];d=this.containment?!(d-this.offset.click.topthis.containment[3])?d:!(d-this.offset.click.topthis.containment[2])?a:!(a-this.offset.click.left').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1E3}).css(b(this).offset()).appendTo("body")})},stop:function(){b("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)})}});b.ui.plugin.add("draggable","opacity",{start:function(c,f){c=b(f.helper);f=b(this).data("draggable").options; +if(c.css("opacity"))f._opacity=c.css("opacity");c.css("opacity",f.opacity)},stop:function(c,f){c=b(this).data("draggable").options;c._opacity&&b(f.helper).css("opacity",c._opacity)}});b.ui.plugin.add("draggable","scroll",{start:function(){var c=b(this).data("draggable");if(c.scrollParent[0]!=document&&c.scrollParent[0].tagName!="HTML")c.overflowOffset=c.scrollParent.offset()},drag:function(c){var f=b(this).data("draggable"),g=f.options,e=false;if(f.scrollParent[0]!=document&&f.scrollParent[0].tagName!= +"HTML"){if(!g.axis||g.axis!="x")if(f.overflowOffset.top+f.scrollParent[0].offsetHeight-c.pageY=0;n--){var q=g.snapElements[n].left,l=q+g.snapElements[n].width,k=g.snapElements[n].top,m=k+g.snapElements[n].height;if(q-a=n&&d<=q||h>=n&&h<=q||dq)&&(e>= +i&&e<=j||a>=i&&a<=j||ej);default:return false}};b.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(c,f){var g=b.ui.ddmanager.droppables[c.options.scope]||[],e=f?f.type:null,a=(c.currentItem||c.element).find(":data(droppable)").andSelf(),d=0;a:for(;d').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(), +top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle= +this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=e.handles||(!b(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne", +nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all")this.handles="n,e,s,w,se,sw,ne,nw";var a=this.handles.split(",");this.handles={};for(var d=0;d');/sw|se|ne|nw/.test(h)&&i.css({zIndex:++e.zIndex});"se"==h&&i.addClass("ui-icon ui-icon-gripsmall-diagonal-se");this.handles[h]=".ui-resizable-"+h;this.element.append(i)}}this._renderAxis=function(j){j=j||this.element;for(var n in this.handles){if(this.handles[n].constructor== +String)this.handles[n]=b(this.handles[n],this.element).show();if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var q=b(this.handles[n],this.element),l=0;l=/sw|ne|nw|se|n|s/.test(n)?q.outerHeight():q.outerWidth();q=["padding",/ne|nw|n/.test(n)?"Top":/se|sw|s/.test(n)?"Bottom":/^e$/.test(n)?"Right":"Left"].join("");j.css(q,l);this._proportionallyResize()}b(this.handles[n])}};this._renderAxis(this.element);this._handles=b(".ui-resizable-handle",this.element).disableSelection(); +this._handles.mouseover(function(){if(!g.resizing){if(this.className)var j=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);g.axis=j&&j[1]?j[1]:"se"}});if(e.autoHide){this._handles.hide();b(this.element).addClass("ui-resizable-autohide").hover(function(){b(this).removeClass("ui-resizable-autohide");g._handles.show()},function(){if(!g.resizing){b(this).addClass("ui-resizable-autohide");g._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var g=function(a){b(a).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()}; +if(this.elementIsWrapper){g(this.element);var e=this.element;e.after(this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);g(this.originalElement);return this},_mouseCapture:function(g){var e=false;for(var a in this.handles)if(b(this.handles[a])[0]==g.target)e=true;return!this.options.disabled&&e},_mouseStart:function(g){var e=this.options,a=this.element.position(), +d=this.element;this.resizing=true;this.documentScroll={top:b(document).scrollTop(),left:b(document).scrollLeft()};if(d.is(".ui-draggable")||/absolute/.test(d.css("position")))d.css({position:"absolute",top:a.top,left:a.left});b.browser.opera&&/relative/.test(d.css("position"))&&d.css({position:"relative",top:"auto",left:"auto"});this._renderProxy();a=c(this.helper.css("left"));var h=c(this.helper.css("top"));if(e.containment){a+=b(e.containment).scrollLeft()||0;h+=b(e.containment).scrollTop()||0}this.offset= +this.helper.offset();this.position={left:a,top:h};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:a,top:h};this.sizeDiff={width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:g.pageX,top:g.pageY};this.aspectRatio=typeof e.aspectRatio=="number"?e.aspectRatio: +this.originalSize.width/this.originalSize.height||1;e=b(".ui-resizable-"+this.axis).css("cursor");b("body").css("cursor",e=="auto"?this.axis+"-resize":e);d.addClass("ui-resizable-resizing");this._propagate("start",g);return true},_mouseDrag:function(g){var e=this.helper,a=this.originalMousePosition,d=this._change[this.axis];if(!d)return false;a=d.apply(this,[g,g.pageX-a.left||0,g.pageY-a.top||0]);if(this._aspectRatio||g.shiftKey)a=this._updateRatio(a,g);a=this._respectSize(a,g);this._propagate("resize", +g);e.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize();this._updateCache(a);this._trigger("resize",g,this.ui());return false},_mouseStop:function(g){this.resizing=false;var e=this.options,a=this;if(this._helper){var d=this._proportionallyResizeElements,h=d.length&&/textarea/i.test(d[0].nodeName);d=h&&b.ui.hasScroll(d[0],"left")?0:a.sizeDiff.height; +h={width:a.size.width-(h?0:a.sizeDiff.width),height:a.size.height-d};d=parseInt(a.element.css("left"),10)+(a.position.left-a.originalPosition.left)||null;var i=parseInt(a.element.css("top"),10)+(a.position.top-a.originalPosition.top)||null;e.animate||this.element.css(b.extend(h,{top:i,left:d}));a.helper.height(a.size.height);a.helper.width(a.size.width);this._helper&&!e.animate&&this._proportionallyResize()}b("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop", +g);this._helper&&this.helper.remove();return false},_updateCache:function(g){this.offset=this.helper.offset();if(f(g.left))this.position.left=g.left;if(f(g.top))this.position.top=g.top;if(f(g.height))this.size.height=g.height;if(f(g.width))this.size.width=g.width},_updateRatio:function(g){var e=this.position,a=this.size,d=this.axis;if(g.height)g.width=a.height*this.aspectRatio;else if(g.width)g.height=a.width/this.aspectRatio;if(d=="sw"){g.left=e.left+(a.width-g.width);g.top=null}if(d=="nw"){g.top= +e.top+(a.height-g.height);g.left=e.left+(a.width-g.width)}return g},_respectSize:function(g){var e=this.options,a=this.axis,d=f(g.width)&&e.maxWidth&&e.maxWidthg.width,j=f(g.height)&&e.minHeight&&e.minHeight>g.height;if(i)g.width=e.minWidth;if(j)g.height=e.minHeight;if(d)g.width=e.maxWidth;if(h)g.height=e.maxHeight;var n=this.originalPosition.left+this.originalSize.width,q=this.position.top+this.size.height, +l=/sw|nw|w/.test(a);a=/nw|ne|n/.test(a);if(i&&l)g.left=n-e.minWidth;if(d&&l)g.left=n-e.maxWidth;if(j&&a)g.top=q-e.minHeight;if(h&&a)g.top=q-e.maxHeight;if((e=!g.width&&!g.height)&&!g.left&&g.top)g.top=null;else if(e&&!g.top&&g.left)g.left=null;return g},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var g=this.helper||this.element,e=0;e');var e=b.browser.msie&&b.browser.version<7,a=e?1:0;e=e?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+e,height:this.element.outerHeight()+e,position:"absolute",left:this.elementOffset.left-a+"px",top:this.elementOffset.top-a+"px",zIndex:++g.zIndex});this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(g,e){return{width:this.originalSize.width+ +e}},w:function(g,e){return{left:this.originalPosition.left+e,width:this.originalSize.width-e}},n:function(g,e,a){return{top:this.originalPosition.top+a,height:this.originalSize.height-a}},s:function(g,e,a){return{height:this.originalSize.height+a}},se:function(g,e,a){return b.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[g,e,a]))},sw:function(g,e,a){return b.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[g,e,a]))},ne:function(g,e,a){return b.extend(this._change.n.apply(this, +arguments),this._change.e.apply(this,[g,e,a]))},nw:function(g,e,a){return b.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[g,e,a]))}},_propagate:function(g,e){b.ui.plugin.call(this,g,[e,this.ui()]);g!="resize"&&this._trigger(g,e,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}});b.extend(b.ui.resizable, +{version:"1.8.6"});b.ui.plugin.add("resizable","alsoResize",{start:function(){var g=b(this).data("resizable").options,e=function(a){b(a).each(function(){var d=b(this);d.data("resizable-alsoresize",{width:parseInt(d.width(),10),height:parseInt(d.height(),10),left:parseInt(d.css("left"),10),top:parseInt(d.css("top"),10),position:d.css("position")})})};if(typeof g.alsoResize=="object"&&!g.alsoResize.parentNode)if(g.alsoResize.length){g.alsoResize=g.alsoResize[0];e(g.alsoResize)}else b.each(g.alsoResize, +function(a){e(a)});else e(g.alsoResize)},resize:function(g,e){var a=b(this).data("resizable");g=a.options;var d=a.originalSize,h=a.originalPosition,i={height:a.size.height-d.height||0,width:a.size.width-d.width||0,top:a.position.top-h.top||0,left:a.position.left-h.left||0},j=function(n,q){b(n).each(function(){var l=b(this),k=b(this).data("resizable-alsoresize"),m={},o=q&&q.length?q:l.parents(e.originalElement[0]).length?["width","height"]:["width","height","top","left"];b.each(o,function(p,s){if((p= +(k[s]||0)+(i[s]||0))&&p>=0)m[s]=p||null});if(b.browser.opera&&/relative/.test(l.css("position"))){a._revertToRelativePosition=true;l.css({position:"absolute",top:"auto",left:"auto"})}l.css(m)})};typeof g.alsoResize=="object"&&!g.alsoResize.nodeType?b.each(g.alsoResize,function(n,q){j(n,q)}):j(g.alsoResize)},stop:function(){var g=b(this).data("resizable"),e=g.options,a=function(d){b(d).each(function(){var h=b(this);h.css({position:h.data("resizable-alsoresize").position})})};if(g._revertToRelativePosition){g._revertToRelativePosition= +false;typeof e.alsoResize=="object"&&!e.alsoResize.nodeType?b.each(e.alsoResize,function(d){a(d)}):a(e.alsoResize)}b(this).removeData("resizable-alsoresize")}});b.ui.plugin.add("resizable","animate",{stop:function(g){var e=b(this).data("resizable"),a=e.options,d=e._proportionallyResizeElements,h=d.length&&/textarea/i.test(d[0].nodeName),i=h&&b.ui.hasScroll(d[0],"left")?0:e.sizeDiff.height;h={width:e.size.width-(h?0:e.sizeDiff.width),height:e.size.height-i};i=parseInt(e.element.css("left"),10)+(e.position.left- +e.originalPosition.left)||null;var j=parseInt(e.element.css("top"),10)+(e.position.top-e.originalPosition.top)||null;e.element.animate(b.extend(h,j&&i?{top:j,left:i}:{}),{duration:a.animateDuration,easing:a.animateEasing,step:function(){var n={width:parseInt(e.element.css("width"),10),height:parseInt(e.element.css("height"),10),top:parseInt(e.element.css("top"),10),left:parseInt(e.element.css("left"),10)};d&&d.length&&b(d[0]).css({width:n.width,height:n.height});e._updateCache(n);e._propagate("resize", +g)}})}});b.ui.plugin.add("resizable","containment",{start:function(){var g=b(this).data("resizable"),e=g.element,a=g.options.containment;if(e=a instanceof b?a.get(0):/parent/.test(a)?e.parent().get(0):a){g.containerElement=b(e);if(/document/.test(a)||a==document){g.containerOffset={left:0,top:0};g.containerPosition={left:0,top:0};g.parentData={element:b(document),left:0,top:0,width:b(document).width(),height:b(document).height()||document.body.parentNode.scrollHeight}}else{var d=b(e),h=[];b(["Top", +"Right","Left","Bottom"]).each(function(n,q){h[n]=c(d.css("padding"+q))});g.containerOffset=d.offset();g.containerPosition=d.position();g.containerSize={height:d.innerHeight()-h[3],width:d.innerWidth()-h[1]};a=g.containerOffset;var i=g.containerSize.height,j=g.containerSize.width;j=b.ui.hasScroll(e,"left")?e.scrollWidth:j;i=b.ui.hasScroll(e)?e.scrollHeight:i;g.parentData={element:e,left:a.left,top:a.top,width:j,height:i}}}},resize:function(g){var e=b(this).data("resizable"),a=e.options,d=e.containerOffset, +h=e.position;g=e._aspectRatio||g.shiftKey;var i={top:0,left:0},j=e.containerElement;if(j[0]!=document&&/static/.test(j.css("position")))i=d;if(h.left<(e._helper?d.left:0)){e.size.width+=e._helper?e.position.left-d.left:e.position.left-i.left;if(g)e.size.height=e.size.width/a.aspectRatio;e.position.left=a.helper?d.left:0}if(h.top<(e._helper?d.top:0)){e.size.height+=e._helper?e.position.top-d.top:e.position.top;if(g)e.size.width=e.size.height*a.aspectRatio;e.position.top=e._helper?d.top:0}e.offset.left= +e.parentData.left+e.position.left;e.offset.top=e.parentData.top+e.position.top;a=Math.abs((e._helper?e.offset.left-i.left:e.offset.left-i.left)+e.sizeDiff.width);d=Math.abs((e._helper?e.offset.top-i.top:e.offset.top-d.top)+e.sizeDiff.height);h=e.containerElement.get(0)==e.element.parent().get(0);i=/relative|absolute/.test(e.containerElement.css("position"));if(h&&i)a-=e.parentData.left;if(a+e.size.width>=e.parentData.width){e.size.width=e.parentData.width-a;if(g)e.size.height=e.size.width/e.aspectRatio}if(d+ +e.size.height>=e.parentData.height){e.size.height=e.parentData.height-d;if(g)e.size.width=e.size.height*e.aspectRatio}},stop:function(){var g=b(this).data("resizable"),e=g.options,a=g.containerOffset,d=g.containerPosition,h=g.containerElement,i=b(g.helper),j=i.offset(),n=i.outerWidth()-g.sizeDiff.width;i=i.outerHeight()-g.sizeDiff.height;g._helper&&!e.animate&&/relative/.test(h.css("position"))&&b(this).css({left:j.left-d.left-a.left,width:n,height:i});g._helper&&!e.animate&&/static/.test(h.css("position"))&& +b(this).css({left:j.left-d.left-a.left,width:n,height:i})}});b.ui.plugin.add("resizable","ghost",{start:function(){var g=b(this).data("resizable"),e=g.options,a=g.size;g.ghost=g.originalElement.clone();g.ghost.css({opacity:0.25,display:"block",position:"relative",height:a.height,width:a.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof e.ghost=="string"?e.ghost:"");g.ghost.appendTo(g.helper)},resize:function(){var g=b(this).data("resizable");g.ghost&&g.ghost.css({position:"relative", +height:g.size.height,width:g.size.width})},stop:function(){var g=b(this).data("resizable");g.ghost&&g.helper&&g.helper.get(0).removeChild(g.ghost.get(0))}});b.ui.plugin.add("resizable","grid",{resize:function(){var g=b(this).data("resizable"),e=g.options,a=g.size,d=g.originalSize,h=g.originalPosition,i=g.axis;e.grid=typeof e.grid=="number"?[e.grid,e.grid]:e.grid;var j=Math.round((a.width-d.width)/(e.grid[0]||1))*(e.grid[0]||1);e=Math.round((a.height-d.height)/(e.grid[1]||1))*(e.grid[1]||1);if(/^(se|s|e)$/.test(i)){g.size.width= +d.width+j;g.size.height=d.height+e}else if(/^(ne)$/.test(i)){g.size.width=d.width+j;g.size.height=d.height+e;g.position.top=h.top-e}else{if(/^(sw)$/.test(i)){g.size.width=d.width+j;g.size.height=d.height+e}else{g.size.width=d.width+j;g.size.height=d.height+e;g.position.top=h.top-e}g.position.left=h.left-j}}});var c=function(g){return parseInt(g,10)||0},f=function(g){return!isNaN(parseInt(g,10))}})(jQuery); +(function(b){b.widget("ui.selectable",b.ui.mouse,{options:{appendTo:"body",autoRefresh:true,distance:0,filter:"*",tolerance:"touch"},_create:function(){var c=this;this.element.addClass("ui-selectable");this.dragged=false;var f;this.refresh=function(){f=b(c.options.filter,c.element[0]);f.each(function(){var g=b(this),e=g.offset();b.data(this,"selectable-item",{element:this,$element:g,left:e.left,top:e.top,right:e.left+g.outerWidth(),bottom:e.top+g.outerHeight(),startselected:false,selected:g.hasClass("ui-selected"), +selecting:g.hasClass("ui-selecting"),unselecting:g.hasClass("ui-unselecting")})})};this.refresh();this.selectees=f.addClass("ui-selectee");this._mouseInit();this.helper=b("
")},destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item");this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable");this._mouseDestroy();return this},_mouseStart:function(c){var f=this;this.opos=[c.pageX, +c.pageY];if(!this.options.disabled){var g=this.options;this.selectees=b(g.filter,this.element[0]);this._trigger("start",c);b(g.appendTo).append(this.helper);this.helper.css({left:c.clientX,top:c.clientY,width:0,height:0});g.autoRefresh&&this.refresh();this.selectees.filter(".ui-selected").each(function(){var e=b.data(this,"selectable-item");e.startselected=true;if(!c.metaKey){e.$element.removeClass("ui-selected");e.selected=false;e.$element.addClass("ui-unselecting");e.unselecting=true;f._trigger("unselecting", +c,{unselecting:e.element})}});b(c.target).parents().andSelf().each(function(){var e=b.data(this,"selectable-item");if(e){var a=!c.metaKey||!e.$element.hasClass("ui-selected");e.$element.removeClass(a?"ui-unselecting":"ui-selected").addClass(a?"ui-selecting":"ui-unselecting");e.unselecting=!a;e.selecting=a;(e.selected=a)?f._trigger("selecting",c,{selecting:e.element}):f._trigger("unselecting",c,{unselecting:e.element});return false}})}},_mouseDrag:function(c){var f=this;this.dragged=true;if(!this.options.disabled){var g= +this.options,e=this.opos[0],a=this.opos[1],d=c.pageX,h=c.pageY;if(e>d){var i=d;d=e;e=i}if(a>h){i=h;h=a;a=i}this.helper.css({left:e,top:a,width:d-e,height:h-a});this.selectees.each(function(){var j=b.data(this,"selectable-item");if(!(!j||j.element==f.element[0])){var n=false;if(g.tolerance=="touch")n=!(j.left>d||j.righth||j.bottome&&j.righta&&j.bottom *",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1E3},_create:function(){this.containerCache={};this.element.addClass("ui-sortable"); +this.refresh();this.floating=this.items.length?/left|right/.test(this.items[0].item.css("float")):false;this.offset=this.element.offset();this._mouseInit()},destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").removeData("sortable").unbind(".sortable");this._mouseDestroy();for(var c=this.items.length-1;c>=0;c--)this.items[c].item.removeData("sortable-item");return this},_setOption:function(c,f){if(c==="disabled"){this.options[c]=f;this.widget()[f?"addClass":"removeClass"]("ui-sortable-disabled")}else b.Widget.prototype._setOption.apply(this, +arguments)},_mouseCapture:function(c,f){if(this.reverting)return false;if(this.options.disabled||this.options.type=="static")return false;this._refreshItems(c);var g=null,e=this;b(c.target).parents().each(function(){if(b.data(this,"sortable-item")==e){g=b(this);return false}});if(b.data(c.target,"sortable-item")==e)g=b(c.target);if(!g)return false;if(this.options.handle&&!f){var a=false;b(this.options.handle,g).find("*").andSelf().each(function(){if(this==c.target)a=true});if(!a)return false}this.currentItem= +g;this._removeCurrentsFromItems();return true},_mouseStart:function(c,f,g){f=this.options;var e=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(c);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");b.extend(this.offset, +{click:{left:c.pageX-this.offset.left,top:c.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(c);this.originalPageX=c.pageX;this.originalPageY=c.pageY;f.cursorAt&&this._adjustOffsetFromHelper(f.cursorAt);this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]};this.helper[0]!=this.currentItem[0]&&this.currentItem.hide();this._createPlaceholder();f.containment&&this._setContainment(); +if(f.cursor){if(b("body").css("cursor"))this._storedCursor=b("body").css("cursor");b("body").css("cursor",f.cursor)}if(f.opacity){if(this.helper.css("opacity"))this._storedOpacity=this.helper.css("opacity");this.helper.css("opacity",f.opacity)}if(f.zIndex){if(this.helper.css("zIndex"))this._storedZIndex=this.helper.css("zIndex");this.helper.css("zIndex",f.zIndex)}if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML")this.overflowOffset=this.scrollParent.offset();this._trigger("start", +c,this._uiHash());this._preserveHelperProportions||this._cacheHelperProportions();if(!g)for(g=this.containers.length-1;g>=0;g--)this.containers[g]._trigger("activate",c,e._uiHash(this));if(b.ui.ddmanager)b.ui.ddmanager.current=this;b.ui.ddmanager&&!f.dropBehaviour&&b.ui.ddmanager.prepareOffsets(this,c);this.dragging=true;this.helper.addClass("ui-sortable-helper");this._mouseDrag(c);return true},_mouseDrag:function(c){this.position=this._generatePosition(c);this.positionAbs=this._convertPositionTo("absolute"); +if(!this.lastPositionAbs)this.lastPositionAbs=this.positionAbs;if(this.options.scroll){var f=this.options,g=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){if(this.overflowOffset.top+this.scrollParent[0].offsetHeight-c.pageY=0;f--){g=this.items[f];var e=g.item[0],a=this._intersectsWithPointer(g);if(a)if(e!=this.currentItem[0]&&this.placeholder[a==1?"next":"prev"]()[0]!=e&&!b.ui.contains(this.placeholder[0],e)&&(this.options.type=="semi-dynamic"?!b.ui.contains(this.element[0],e):true)){this.direction=a==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(g))this._rearrange(c, +g);else break;this._trigger("change",c,this._uiHash());break}}this._contactContainers(c);b.ui.ddmanager&&b.ui.ddmanager.drag(this,c);this._trigger("sort",c,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(c,f){if(c){b.ui.ddmanager&&!this.options.dropBehaviour&&b.ui.ddmanager.drop(this,c);if(this.options.revert){var g=this;f=g.placeholder.offset();g.reverting=true;b(this.helper).animate({left:f.left-this.offset.parent.left-g.margins.left+(this.offsetParent[0]== +document.body?0:this.offsetParent[0].scrollLeft),top:f.top-this.offset.parent.top-g.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){g._clear(c)})}else this._clear(c,f);return false}},cancel:function(){var c=this;if(this.dragging){this._mouseUp();this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var f=this.containers.length-1;f>=0;f--){this.containers[f]._trigger("deactivate", +null,c._uiHash(this));if(this.containers[f].containerCache.over){this.containers[f]._trigger("out",null,c._uiHash(this));this.containers[f].containerCache.over=0}}}this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]);this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove();b.extend(this,{helper:null,dragging:false,reverting:false,_noFinalSort:null});this.domPosition.prev?b(this.domPosition.prev).after(this.currentItem): +b(this.domPosition.parent).prepend(this.currentItem);return this},serialize:function(c){var f=this._getItemsAsjQuery(c&&c.connected),g=[];c=c||{};b(f).each(function(){var e=(b(c.item||this).attr(c.attribute||"id")||"").match(c.expression||/(.+)[-=_](.+)/);if(e)g.push((c.key||e[1]+"[]")+"="+(c.key&&c.expression?e[1]:e[2]))});!g.length&&c.key&&g.push(c.key+"=");return g.join("&")},toArray:function(c){var f=this._getItemsAsjQuery(c&&c.connected),g=[];c=c||{};f.each(function(){g.push(b(c.item||this).attr(c.attribute|| +"id")||"")});return g},_intersectsWith:function(c){var f=this.positionAbs.left,g=f+this.helperProportions.width,e=this.positionAbs.top,a=e+this.helperProportions.height,d=c.left,h=d+c.width,i=c.top,j=i+c.height,n=this.offset.click.top,q=this.offset.click.left;n=e+n>i&&e+nd&&f+qc[this.floating?"width":"height"]?n:d0?"down":"up")}, +_getDragHorizontalDirection:function(){var c=this.positionAbs.left-this.lastPositionAbs.left;return c!=0&&(c>0?"right":"left")},refresh:function(c){this._refreshItems(c);this.refreshPositions();return this},_connectWith:function(){var c=this.options;return c.connectWith.constructor==String?[c.connectWith]:c.connectWith},_getItemsAsjQuery:function(c){var f=[],g=[],e=this._connectWith();if(e&&c)for(c=e.length-1;c>=0;c--)for(var a=b(e[c]),d=a.length-1;d>=0;d--){var h=b.data(a[d],"sortable");if(h&&h!= +this&&!h.options.disabled)g.push([b.isFunction(h.options.items)?h.options.items.call(h.element):b(h.options.items,h.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),h])}g.push([b.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):b(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]);for(c=g.length-1;c>=0;c--)g[c][0].each(function(){f.push(this)});return b(f)},_removeCurrentsFromItems:function(){for(var c= +this.currentItem.find(":data(sortable-item)"),f=0;f=0;a--)for(var d=b(e[a]),h=d.length-1;h>=0;h--){var i=b.data(d[h],"sortable"); +if(i&&i!=this&&!i.options.disabled){g.push([b.isFunction(i.options.items)?i.options.items.call(i.element[0],c,{item:this.currentItem}):b(i.options.items,i.element),i]);this.containers.push(i)}}for(a=g.length-1;a>=0;a--){c=g[a][1];e=g[a][0];h=0;for(d=e.length;h= +0;f--){var g=this.items[f],e=this.options.toleranceElement?b(this.options.toleranceElement,g.item):g.item;if(!c){g.width=e.outerWidth();g.height=e.outerHeight()}e=e.offset();g.left=e.left;g.top=e.top}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(f=this.containers.length-1;f>=0;f--){e=this.containers[f].element.offset();this.containers[f].containerCache.left=e.left;this.containers[f].containerCache.top=e.top;this.containers[f].containerCache.width= +this.containers[f].element.outerWidth();this.containers[f].containerCache.height=this.containers[f].element.outerHeight()}return this},_createPlaceholder:function(c){var f=c||this,g=f.options;if(!g.placeholder||g.placeholder.constructor==String){var e=g.placeholder;g.placeholder={element:function(){var a=b(document.createElement(f.currentItem[0].nodeName)).addClass(e||f.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];if(!e)a.style.visibility="hidden";return a}, +update:function(a,d){if(!(e&&!g.forcePlaceholderSize)){d.height()||d.height(f.currentItem.innerHeight()-parseInt(f.currentItem.css("paddingTop")||0,10)-parseInt(f.currentItem.css("paddingBottom")||0,10));d.width()||d.width(f.currentItem.innerWidth()-parseInt(f.currentItem.css("paddingLeft")||0,10)-parseInt(f.currentItem.css("paddingRight")||0,10))}}}}f.placeholder=b(g.placeholder.element.call(f.element,f.currentItem));f.currentItem.after(f.placeholder);g.placeholder.update(f,f.placeholder)},_contactContainers:function(c){for(var f= +null,g=null,e=this.containers.length-1;e>=0;e--)if(!b.ui.contains(this.currentItem[0],this.containers[e].element[0]))if(this._intersectsWith(this.containers[e].containerCache)){if(!(f&&b.ui.contains(this.containers[e].element[0],f.element[0]))){f=this.containers[e];g=e}}else if(this.containers[e].containerCache.over){this.containers[e]._trigger("out",c,this._uiHash(this));this.containers[e].containerCache.over=0}if(f)if(this.containers.length===1){this.containers[g]._trigger("over",c,this._uiHash(this)); +this.containers[g].containerCache.over=1}else if(this.currentContainer!=this.containers[g]){f=1E4;e=null;for(var a=this.positionAbs[this.containers[g].floating?"left":"top"],d=this.items.length-1;d>=0;d--)if(b.ui.contains(this.containers[g].element[0],this.items[d].item[0])){var h=this.items[d][this.containers[g].floating?"left":"top"];if(Math.abs(h-a)this.containment[2])a=this.containment[2]+this.offset.click.left;if(c.pageY-this.offset.click.top>this.containment[3])d=this.containment[3]+this.offset.click.top}if(f.grid){d=this.originalPageY+Math.round((d-this.originalPageY)/f.grid[1])*f.grid[1];d=this.containment?!(d-this.offset.click.topthis.containment[3])? +d:!(d-this.offset.click.topthis.containment[2])?a:!(a-this.offset.click.left=0;e--)if(b.ui.contains(this.containers[e].element[0],this.currentItem[0])&&!f){g.push(function(a){return function(d){a._trigger("receive", +d,this._uiHash(this))}}.call(this,this.containers[e]));g.push(function(a){return function(d){a._trigger("update",d,this._uiHash(this))}}.call(this,this.containers[e]))}}for(e=this.containers.length-1;e>=0;e--){f||g.push(function(a){return function(d){a._trigger("deactivate",d,this._uiHash(this))}}.call(this,this.containers[e]));if(this.containers[e].containerCache.over){g.push(function(a){return function(d){a._trigger("out",d,this._uiHash(this))}}.call(this,this.containers[e]));this.containers[e].containerCache.over= +0}}this._storedCursor&&b("body").css("cursor",this._storedCursor);this._storedOpacity&&this.helper.css("opacity",this._storedOpacity);if(this._storedZIndex)this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex);this.dragging=false;if(this.cancelHelperRemoval){if(!f){this._trigger("beforeStop",c,this._uiHash());for(e=0;e").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0});l.wrap(m);m=l.parent();if(l.css("position")=="static"){m.css({position:"relative"});l.css({position:"relative"})}else{b.extend(k, +{position:l.css("position"),zIndex:l.css("z-index")});b.each(["top","left","bottom","right"],function(o,p){k[p]=l.css(p);if(isNaN(parseInt(k[p],10)))k[p]="auto"});l.css({position:"relative",top:0,left:0})}return m.css(k).show()},removeWrapper:function(l){if(l.parent().is(".ui-effects-wrapper"))return l.parent().replaceWith(l);return l},setTransition:function(l,k,m,o){o=o||{};b.each(k,function(p,s){unit=l.cssUnit(s);if(unit[0]>0)o[s]=unit[0]*m+unit[1]});return o}});b.fn.extend({effect:function(l){var k= +h.apply(this,arguments),m={options:k[1],duration:k[2],callback:k[3]};k=m.options.mode;var o=b.effects[l];if(b.fx.off||!o)return k?this[k](m.duration,m.callback):this.each(function(){m.callback&&m.callback.call(this)});return o.call(this,m)},_show:b.fn.show,show:function(l){if(i(l))return this._show.apply(this,arguments);else{var k=h.apply(this,arguments);k[1].mode="show";return this.effect.apply(this,k)}},_hide:b.fn.hide,hide:function(l){if(i(l))return this._hide.apply(this,arguments);else{var k= +h.apply(this,arguments);k[1].mode="hide";return this.effect.apply(this,k)}},__toggle:b.fn.toggle,toggle:function(l){if(i(l)||typeof l==="boolean"||b.isFunction(l))return this.__toggle.apply(this,arguments);else{var k=h.apply(this,arguments);k[1].mode="toggle";return this.effect.apply(this,k)}},cssUnit:function(l){var k=this.css(l),m=[];b.each(["em","px","%","pt"],function(o,p){if(k.indexOf(p)>0)m=[parseFloat(k),p]});return m}});b.easing.jswing=b.easing.swing;b.extend(b.easing,{def:"easeOutQuad",swing:function(l, +k,m,o,p){return b.easing[b.easing.def](l,k,m,o,p)},easeInQuad:function(l,k,m,o,p){return o*(k/=p)*k+m},easeOutQuad:function(l,k,m,o,p){return-o*(k/=p)*(k-2)+m},easeInOutQuad:function(l,k,m,o,p){if((k/=p/2)<1)return o/2*k*k+m;return-o/2*(--k*(k-2)-1)+m},easeInCubic:function(l,k,m,o,p){return o*(k/=p)*k*k+m},easeOutCubic:function(l,k,m,o,p){return o*((k=k/p-1)*k*k+1)+m},easeInOutCubic:function(l,k,m,o,p){if((k/=p/2)<1)return o/2*k*k*k+m;return o/2*((k-=2)*k*k+2)+m},easeInQuart:function(l,k,m,o,p){return o* +(k/=p)*k*k*k+m},easeOutQuart:function(l,k,m,o,p){return-o*((k=k/p-1)*k*k*k-1)+m},easeInOutQuart:function(l,k,m,o,p){if((k/=p/2)<1)return o/2*k*k*k*k+m;return-o/2*((k-=2)*k*k*k-2)+m},easeInQuint:function(l,k,m,o,p){return o*(k/=p)*k*k*k*k+m},easeOutQuint:function(l,k,m,o,p){return o*((k=k/p-1)*k*k*k*k+1)+m},easeInOutQuint:function(l,k,m,o,p){if((k/=p/2)<1)return o/2*k*k*k*k*k+m;return o/2*((k-=2)*k*k*k*k+2)+m},easeInSine:function(l,k,m,o,p){return-o*Math.cos(k/p*(Math.PI/2))+o+m},easeOutSine:function(l, +k,m,o,p){return o*Math.sin(k/p*(Math.PI/2))+m},easeInOutSine:function(l,k,m,o,p){return-o/2*(Math.cos(Math.PI*k/p)-1)+m},easeInExpo:function(l,k,m,o,p){return k==0?m:o*Math.pow(2,10*(k/p-1))+m},easeOutExpo:function(l,k,m,o,p){return k==p?m+o:o*(-Math.pow(2,-10*k/p)+1)+m},easeInOutExpo:function(l,k,m,o,p){if(k==0)return m;if(k==p)return m+o;if((k/=p/2)<1)return o/2*Math.pow(2,10*(k-1))+m;return o/2*(-Math.pow(2,-10*--k)+2)+m},easeInCirc:function(l,k,m,o,p){return-o*(Math.sqrt(1-(k/=p)*k)-1)+m},easeOutCirc:function(l, +k,m,o,p){return o*Math.sqrt(1-(k=k/p-1)*k)+m},easeInOutCirc:function(l,k,m,o,p){if((k/=p/2)<1)return-o/2*(Math.sqrt(1-k*k)-1)+m;return o/2*(Math.sqrt(1-(k-=2)*k)+1)+m},easeInElastic:function(l,k,m,o,p){l=1.70158;var s=0,r=o;if(k==0)return m;if((k/=p)==1)return m+o;s||(s=p*0.3);if(r").css({position:"absolute",visibility:"visible",left:-j*(d/g),top:-i*(h/f)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:d/g,height:h/f,left:a.left+j*(d/g)+(c.options.mode=="show"?(j-Math.floor(g/2))*(d/g):0),top:a.top+i*(h/f)+(c.options.mode=="show"?(i-Math.floor(f/2))*(h/f):0),opacity:c.options.mode=="show"?0:1}).animate({left:a.left+j*(d/g)+(c.options.mode=="show"?0:(j-Math.floor(g/2))*(d/g)),top:a.top+ +i*(h/f)+(c.options.mode=="show"?0:(i-Math.floor(f/2))*(h/f)),opacity:c.options.mode=="show"?1:0},c.duration||500);setTimeout(function(){c.options.mode=="show"?e.css({visibility:"visible"}):e.css({visibility:"visible"}).hide();c.callback&&c.callback.apply(e[0]);e.dequeue();b("div.ui-effects-explode").remove()},c.duration||500)})}})(jQuery); +(function(b){b.effects.fade=function(c){return this.queue(function(){var f=b(this),g=b.effects.setMode(f,c.options.mode||"hide");f.animate({opacity:g},{queue:false,duration:c.duration,easing:c.options.easing,complete:function(){c.callback&&c.callback.apply(this,arguments);f.dequeue()}})})}})(jQuery); +(function(b){b.effects.fold=function(c){return this.queue(function(){var f=b(this),g=["position","top","left"],e=b.effects.setMode(f,c.options.mode||"hide"),a=c.options.size||15,d=!!c.options.horizFirst,h=c.duration?c.duration/2:b.fx.speeds._default/2;b.effects.save(f,g);f.show();var i=b.effects.createWrapper(f).css({overflow:"hidden"}),j=e=="show"!=d,n=j?["width","height"]:["height","width"];j=j?[i.width(),i.height()]:[i.height(),i.width()];var q=/([0-9]+)%/.exec(a);if(q)a=parseInt(q[1],10)/100* +j[e=="hide"?0:1];if(e=="show")i.css(d?{height:0,width:a}:{height:a,width:0});d={};q={};d[n[0]]=e=="show"?j[0]:a;q[n[1]]=e=="show"?j[1]:0;i.animate(d,h,c.options.easing).animate(q,h,c.options.easing,function(){e=="hide"&&f.hide();b.effects.restore(f,g);b.effects.removeWrapper(f);c.callback&&c.callback.apply(f[0],arguments);f.dequeue()})})}})(jQuery); +(function(b){b.effects.highlight=function(c){return this.queue(function(){var f=b(this),g=["backgroundImage","backgroundColor","opacity"],e=b.effects.setMode(f,c.options.mode||"show"),a={backgroundColor:f.css("backgroundColor")};if(e=="hide")a.opacity=0;b.effects.save(f,g);f.show().css({backgroundImage:"none",backgroundColor:c.options.color||"#ffff99"}).animate(a,{queue:false,duration:c.duration,easing:c.options.easing,complete:function(){e=="hide"&&f.hide();b.effects.restore(f,g);e=="show"&&!b.support.opacity&& +this.style.removeAttribute("filter");c.callback&&c.callback.apply(this,arguments);f.dequeue()}})})}})(jQuery); +(function(b){b.effects.pulsate=function(c){return this.queue(function(){var f=b(this),g=b.effects.setMode(f,c.options.mode||"show");times=(c.options.times||5)*2-1;duration=c.duration?c.duration/2:b.fx.speeds._default/2;isVisible=f.is(":visible");animateTo=0;if(!isVisible){f.css("opacity",0).show();animateTo=1}if(g=="hide"&&isVisible||g=="show"&&!isVisible)times--;for(g=0;g').appendTo(document.body).addClass(c.options.className).css({top:e.top,left:e.left,height:f.innerHeight(),width:f.innerWidth(),position:"absolute"}).animate(g,c.duration,c.options.easing,function(){a.remove();c.callback&&c.callback.apply(f[0],arguments); +f.dequeue()})})}})(jQuery); +(function(b){b.widget("ui.accordion",{options:{active:0,animated:"slide",autoHeight:true,clearStyle:false,collapsible:false,event:"click",fillSpace:false,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:false,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var c=this,f=c.options;c.running=0;c.element.addClass("ui-accordion ui-widget ui-helper-reset").children("li").addClass("ui-accordion-li-fix");c.headers= +c.element.find(f.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){f.disabled||b(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){f.disabled||b(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){f.disabled||b(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){f.disabled||b(this).removeClass("ui-state-focus")});c.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom"); +if(f.navigation){var g=c.element.find("a").filter(f.navigationFilter).eq(0);if(g.length){var e=g.closest(".ui-accordion-header");c.active=e.length?e:g.closest(".ui-accordion-content").prev()}}c.active=c._findActive(c.active||f.active).addClass("ui-state-default ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top");c.active.next().addClass("ui-accordion-content-active");c._createIcons();c.resize();c.element.attr("role","tablist");c.headers.attr("role","tab").bind("keydown.accordion", +function(a){return c._keydown(a)}).next().attr("role","tabpanel");c.headers.not(c.active||"").attr({"aria-expanded":"false",tabIndex:-1}).next().hide();c.active.length?c.active.attr({"aria-expanded":"true",tabIndex:0}):c.headers.eq(0).attr("tabIndex",0);b.browser.safari||c.headers.find("a").attr("tabIndex",-1);f.event&&c.headers.bind(f.event.split(" ").join(".accordion ")+".accordion",function(a){c._clickHandler.call(c,a,this);a.preventDefault()})},_createIcons:function(){var c=this.options;if(c.icons){b("").addClass("ui-icon "+ +c.icons.header).prependTo(this.headers);this.active.children(".ui-icon").toggleClass(c.icons.header).toggleClass(c.icons.headerSelected);this.element.addClass("ui-accordion-icons")}},_destroyIcons:function(){this.headers.children(".ui-icon").remove();this.element.removeClass("ui-accordion-icons")},destroy:function(){var c=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role");this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("tabIndex"); +this.headers.find("a").removeAttr("tabIndex");this._destroyIcons();var f=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled");if(c.autoHeight||c.fillHeight)f.css("height","");return b.Widget.prototype.destroy.call(this)},_setOption:function(c,f){b.Widget.prototype._setOption.apply(this,arguments);c=="active"&&this.activate(f);if(c=="icons"){this._destroyIcons(); +f&&this._createIcons()}if(c=="disabled")this.headers.add(this.headers.next())[f?"addClass":"removeClass"]("ui-accordion-disabled ui-state-disabled")},_keydown:function(c){if(!(this.options.disabled||c.altKey||c.ctrlKey)){var f=b.ui.keyCode,g=this.headers.length,e=this.headers.index(c.target),a=false;switch(c.keyCode){case f.RIGHT:case f.DOWN:a=this.headers[(e+1)%g];break;case f.LEFT:case f.UP:a=this.headers[(e-1+g)%g];break;case f.SPACE:case f.ENTER:this._clickHandler({target:c.target},c.target); +c.preventDefault()}if(a){b(c.target).attr("tabIndex",-1);b(a).attr("tabIndex",0);a.focus();return false}return true}},resize:function(){var c=this.options,f;if(c.fillSpace){if(b.browser.msie){var g=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}f=this.element.parent().height();b.browser.msie&&this.element.parent().css("overflow",g);this.headers.each(function(){f-=b(this).outerHeight(true)});this.headers.next().each(function(){b(this).height(Math.max(0,f-b(this).innerHeight()+ +b(this).height()))}).css("overflow","auto")}else if(c.autoHeight){f=0;this.headers.next().each(function(){f=Math.max(f,b(this).height("").height())}).height(f)}return this},activate:function(c){this.options.active=c;c=this._findActive(c)[0];this._clickHandler({target:c},c);return this},_findActive:function(c){return c?typeof c==="number"?this.headers.filter(":eq("+c+")"):this.headers.not(this.headers.not(c)):c===false?b([]):this.headers.filter(":eq(0)")},_clickHandler:function(c,f){var g=this.options; +if(!g.disabled)if(c.target){c=b(c.currentTarget||f);f=c[0]===this.active[0];g.active=g.collapsible&&f?false:this.headers.index(c);if(!(this.running||!g.collapsible&&f)){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(g.icons.headerSelected).addClass(g.icons.header);if(!f){c.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").children(".ui-icon").removeClass(g.icons.header).addClass(g.icons.headerSelected); +c.next().addClass("ui-accordion-content-active")}d=c.next();e=this.active.next();a={options:g,newHeader:f&&g.collapsible?b([]):c,oldHeader:this.active,newContent:f&&g.collapsible?b([]):d,oldContent:e};g=this.headers.index(this.active[0])>this.headers.index(c[0]);this.active=f?b([]):c;this._toggle(d,e,a,f,g)}}else if(g.collapsible){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(g.icons.headerSelected).addClass(g.icons.header); +this.active.next().addClass("ui-accordion-content-active");var e=this.active.next(),a={options:g,newHeader:b([]),oldHeader:g.active,newContent:b([]),oldContent:e},d=this.active=b([]);this._toggle(d,e,a)}},_toggle:function(c,f,g,e,a){var d=this,h=d.options;d.toShow=c;d.toHide=f;d.data=g;var i=function(){if(d)return d._completed.apply(d,arguments)};d._trigger("changestart",null,d.data);d.running=f.size()===0?c.size():f.size();if(h.animated){g={};g=h.collapsible&&e?{toShow:b([]),toHide:f,complete:i, +down:a,autoHeight:h.autoHeight||h.fillSpace}:{toShow:c,toHide:f,complete:i,down:a,autoHeight:h.autoHeight||h.fillSpace};if(!h.proxied)h.proxied=h.animated;if(!h.proxiedDuration)h.proxiedDuration=h.duration;h.animated=b.isFunction(h.proxied)?h.proxied(g):h.proxied;h.duration=b.isFunction(h.proxiedDuration)?h.proxiedDuration(g):h.proxiedDuration;e=b.ui.accordion.animations;var j=h.duration,n=h.animated;if(n&&!e[n]&&!b.easing[n])n="slide";e[n]||(e[n]=function(q){this.slide(q,{easing:n,duration:j||700})}); +e[n](g)}else{if(h.collapsible&&e)c.toggle();else{f.hide();c.show()}i(true)}f.prev().attr({"aria-expanded":"false",tabIndex:-1}).blur();c.prev().attr({"aria-expanded":"true",tabIndex:0}).focus()},_completed:function(c){this.running=c?0:--this.running;if(!this.running){this.options.clearStyle&&this.toShow.add(this.toHide).css({height:"",overflow:""});this.toHide.removeClass("ui-accordion-content-active");this._trigger("change",null,this.data)}}});b.extend(b.ui.accordion,{version:"1.8.6",animations:{slide:function(c, +f){c=b.extend({easing:"swing",duration:300},c,f);if(c.toHide.size())if(c.toShow.size()){var g=c.toShow.css("overflow"),e=0,a={},d={},h;f=c.toShow;h=f[0].style.width;f.width(parseInt(f.parent().width(),10)-parseInt(f.css("paddingLeft"),10)-parseInt(f.css("paddingRight"),10)-(parseInt(f.css("borderLeftWidth"),10)||0)-(parseInt(f.css("borderRightWidth"),10)||0));b.each(["height","paddingTop","paddingBottom"],function(i,j){d[j]="hide";i=(""+b.css(c.toShow[0],j)).match(/^([\d+-.]+)(.*)$/);a[j]={value:i[1], +unit:i[2]||"px"}});c.toShow.css({height:0,overflow:"hidden"}).show();c.toHide.filter(":hidden").each(c.complete).end().filter(":visible").animate(d,{step:function(i,j){if(j.prop=="height")e=j.end-j.start===0?0:(j.now-j.start)/(j.end-j.start);c.toShow[0].style[j.prop]=e*a[j.prop].value+a[j.prop].unit},duration:c.duration,easing:c.easing,complete:function(){c.autoHeight||c.toShow.css("height","");c.toShow.css({width:h,overflow:g});c.complete()}})}else c.toHide.animate({height:"hide",paddingTop:"hide", +paddingBottom:"hide"},c);else c.toShow.animate({height:"show",paddingTop:"show",paddingBottom:"show"},c)},bounceslide:function(c){this.slide(c,{easing:c.down?"easeOutBounce":"swing",duration:c.down?1E3:200})}}})})(jQuery); +(function(b){b.widget("ui.autocomplete",{options:{appendTo:"body",delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null},_create:function(){var c=this,f=this.element[0].ownerDocument,g;this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(e){if(!(c.options.disabled||c.element.attr("readonly"))){g=false;var a=b.ui.keyCode;switch(e.keyCode){case a.PAGE_UP:c._move("previousPage", +e);break;case a.PAGE_DOWN:c._move("nextPage",e);break;case a.UP:c._move("previous",e);e.preventDefault();break;case a.DOWN:c._move("next",e);e.preventDefault();break;case a.ENTER:case a.NUMPAD_ENTER:if(c.menu.active){g=true;e.preventDefault()}case a.TAB:if(!c.menu.active)return;c.menu.select(e);break;case a.ESCAPE:c.element.val(c.term);c.close(e);break;default:clearTimeout(c.searching);c.searching=setTimeout(function(){if(c.term!=c.element.val()){c.selectedItem=null;c.search(null,e)}},c.options.delay); +break}}}).bind("keypress.autocomplete",function(e){if(g){g=false;e.preventDefault()}}).bind("focus.autocomplete",function(){if(!c.options.disabled){c.selectedItem=null;c.previous=c.element.val()}}).bind("blur.autocomplete",function(e){if(!c.options.disabled){clearTimeout(c.searching);c.closing=setTimeout(function(){c.close(e);c._change(e)},150)}});this._initSource();this.response=function(){return c._response.apply(c,arguments)};this.menu=b("
    ").addClass("ui-autocomplete").appendTo(b(this.options.appendTo|| +"body",f)[0]).mousedown(function(e){var a=c.menu.element[0];b(e.target).closest(".ui-menu-item").length||setTimeout(function(){b(document).one("mousedown",function(d){d.target!==c.element[0]&&d.target!==a&&!b.ui.contains(a,d.target)&&c.close()})},1);setTimeout(function(){clearTimeout(c.closing)},13)}).menu({focus:function(e,a){a=a.item.data("item.autocomplete");false!==c._trigger("focus",e,{item:a})&&/^key/.test(e.originalEvent.type)&&c.element.val(a.value)},selected:function(e,a){a=a.item.data("item.autocomplete"); +var d=c.previous;if(c.element[0]!==f.activeElement){c.element.focus();c.previous=d;setTimeout(function(){c.previous=d},1)}false!==c._trigger("select",e,{item:a})&&c.element.val(a.value);c.term=c.element.val();c.close(e);c.selectedItem=a},blur:function(){c.menu.element.is(":visible")&&c.element.val()!==c.term&&c.element.val(c.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu");b.fn.bgiframe&&this.menu.element.bgiframe()},destroy:function(){this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup"); +this.menu.element.remove();b.Widget.prototype.destroy.call(this)},_setOption:function(c,f){b.Widget.prototype._setOption.apply(this,arguments);c==="source"&&this._initSource();if(c==="appendTo")this.menu.element.appendTo(b(f||"body",this.element[0].ownerDocument)[0])},_initSource:function(){var c=this,f,g;if(b.isArray(this.options.source)){f=this.options.source;this.source=function(e,a){a(b.ui.autocomplete.filter(f,e.term))}}else if(typeof this.options.source==="string"){g=this.options.source;this.source= +function(e,a){c.xhr&&c.xhr.abort();c.xhr=b.getJSON(g,e,function(d,h,i){i===c.xhr&&a(d);c.xhr=null})}}else this.source=this.options.source},search:function(c,f){c=c!=null?c:this.element.val();this.term=this.element.val();if(c.length").data("item.autocomplete",f).append(b("").text(f.label)).appendTo(c)},_move:function(c,f){if(this.menu.element.is(":visible"))if(this.menu.first()&&/^previous/.test(c)||this.menu.last()&&/^next/.test(c)){this.element.val(this.term);this.menu.deactivate()}else this.menu[c](f);else this.search(null,f)},widget:function(){return this.menu.element}});b.extend(b.ui.autocomplete,{escapeRegex:function(c){return c.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, +"\\$&")},filter:function(c,f){var g=new RegExp(b.ui.autocomplete.escapeRegex(f),"i");return b.grep(c,function(e){return g.test(e.label||e.value||e)})}})})(jQuery); +(function(b){b.widget("ui.menu",{_create:function(){var c=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(f){if(b(f.target).closest(".ui-menu-item a").length){f.preventDefault();c.select(f)}});this.refresh()},refresh:function(){var c=this;this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem").children("a").addClass("ui-corner-all").attr("tabindex", +-1).mouseenter(function(f){c.activate(f,b(this).parent())}).mouseleave(function(){c.deactivate()})},activate:function(c,f){this.deactivate();if(this.hasScroll()){var g=f.offset().top-this.element.offset().top,e=this.element.attr("scrollTop"),a=this.element.height();if(g<0)this.element.attr("scrollTop",e+g);else g>=a&&this.element.attr("scrollTop",e+g-a+f.height())}this.active=f.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end();this._trigger("focus",c,{item:f})}, +deactivate:function(){if(this.active){this.active.children("a").removeClass("ui-state-hover").removeAttr("id");this._trigger("blur");this.active=null}},next:function(c){this.move("next",".ui-menu-item:first",c)},previous:function(c){this.move("prev",".ui-menu-item:last",c)},first:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},last:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},move:function(c,f,g){if(this.active){c=this.active[c+"All"](".ui-menu-item").eq(0); +c.length?this.activate(g,c):this.activate(g,this.element.children(f))}else this.activate(g,this.element.children(f))},nextPage:function(c){if(this.hasScroll())if(!this.active||this.last())this.activate(c,this.element.children(".ui-menu-item:first"));else{var f=this.active.offset().top,g=this.element.height(),e=this.element.children(".ui-menu-item").filter(function(){var a=b(this).offset().top-f-g+b(this).height();return a<10&&a>-10});e.length||(e=this.element.children(".ui-menu-item:last"));this.activate(c, +e)}else this.activate(c,this.element.children(".ui-menu-item").filter(!this.active||this.last()?":first":":last"))},previousPage:function(c){if(this.hasScroll())if(!this.active||this.first())this.activate(c,this.element.children(".ui-menu-item:last"));else{var f=this.active.offset().top,g=this.element.height();result=this.element.children(".ui-menu-item").filter(function(){var e=b(this).offset().top-f+g-b(this).height();return e<10&&e>-10});result.length||(result=this.element.children(".ui-menu-item:first")); +this.activate(c,result)}else this.activate(c,this.element.children(".ui-menu-item").filter(!this.active||this.first()?":last":":first"))},hasScroll:function(){return this.element.height()").addClass("ui-button-text").html(this.options.label).appendTo(e.empty()).text(),d=this.options.icons,h=d.primary&&d.secondary;if(d.primary||d.secondary){e.addClass("ui-button-text-icon"+(h?"s":d.primary?"-primary":"-secondary"));d.primary&&e.prepend("");d.secondary&&e.append("");if(!this.options.text){e.addClass(h?"ui-button-icons-only":"ui-button-icon-only").removeClass("ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary"); +this.hasTitle||e.attr("title",a)}}else e.addClass("ui-button-text-only")}}});b.widget("ui.buttonset",{_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(e,a){e==="disabled"&&this.buttons.button("option",e,a);b.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){this.buttons=this.element.find(":button, :submit, :reset, :checkbox, :radio, a, :data(button)").filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return b(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":visible").filter(":first").addClass("ui-corner-left").end().filter(":last").addClass("ui-corner-right").end().end().end()}, +destroy:function(){this.element.removeClass("ui-buttonset");this.buttons.map(function(){return b(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy");b.Widget.prototype.destroy.call(this)}})})(jQuery); +(function(b,c){function f(){this.debug=false;this._curInst=null;this._keyEvent=false;this._disabledInputs=[];this._inDialog=this._datepickerShowing=false;this._mainDivId="ui-datepicker-div";this._inlineClass="ui-datepicker-inline";this._appendClass="ui-datepicker-append";this._triggerClass="ui-datepicker-trigger";this._dialogClass="ui-datepicker-dialog";this._disableClass="ui-datepicker-disabled";this._unselectableClass="ui-datepicker-unselectable";this._currentClass="ui-datepicker-current-day";this._dayOverClass= +"ui-datepicker-days-cell-over";this.regional=[];this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su", +"Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:false,showMonthAfterYear:false,yearSuffix:""};this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:false,hideIfNoPrevNext:false,navigationAsDateFormat:false,gotoCurrent:false,changeMonth:false,changeYear:false,yearRange:"c-10:c+10",showOtherMonths:false,selectOtherMonths:false,showWeek:false,calculateWeek:this.iso8601Week,shortYearCutoff:"+10", +minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:true,showButtonPanel:false,autoSize:false};b.extend(this._defaults,this.regional[""]);this.dpDiv=b('
    ')}function g(a,d){b.extend(a, +d);for(var h in d)if(d[h]==null||d[h]==c)a[h]=d[h];return a}b.extend(b.ui,{datepicker:{version:"1.8.6"}});var e=(new Date).getTime();b.extend(f.prototype,{markerClassName:"hasDatepicker",log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(a){g(this._defaults,a||{});return this},_attachDatepicker:function(a,d){var h=null;for(var i in this._defaults){var j=a.getAttribute("date:"+i);if(j){h=h||{};try{h[i]=eval(j)}catch(n){h[i]= +j}}}i=a.nodeName.toLowerCase();j=i=="div"||i=="span";if(!a.id){this.uuid+=1;a.id="dp"+this.uuid}var q=this._newInst(b(a),j);q.settings=b.extend({},d||{},h||{});if(i=="input")this._connectDatepicker(a,q);else j&&this._inlineDatepicker(a,q)},_newInst:function(a,d){return{id:a[0].id.replace(/([^A-Za-z0-9_-])/g,"\\\\$1"),input:a,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:d,dpDiv:!d?this.dpDiv:b('
    ')}}, +_connectDatepicker:function(a,d){var h=b(a);d.append=b([]);d.trigger=b([]);if(!h.hasClass(this.markerClassName)){this._attachments(h,d);h.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker",function(i,j,n){d.settings[j]=n}).bind("getData.datepicker",function(i,j){return this._get(d,j)});this._autoSize(d);b.data(a,"datepicker",d)}},_attachments:function(a,d){var h=this._get(d,"appendText"),i=this._get(d,"isRTL");d.append&& +d.append.remove();if(h){d.append=b(''+h+"");a[i?"before":"after"](d.append)}a.unbind("focus",this._showDatepicker);d.trigger&&d.trigger.remove();h=this._get(d,"showOn");if(h=="focus"||h=="both")a.focus(this._showDatepicker);if(h=="button"||h=="both"){h=this._get(d,"buttonText");var j=this._get(d,"buttonImage");d.trigger=b(this._get(d,"buttonImageOnly")?b("").addClass(this._triggerClass).attr({src:j,alt:h,title:h}):b('').addClass(this._triggerClass).html(j== +""?h:b("").attr({src:j,alt:h,title:h})));a[i?"before":"after"](d.trigger);d.trigger.click(function(){b.datepicker._datepickerShowing&&b.datepicker._lastInput==a[0]?b.datepicker._hideDatepicker():b.datepicker._showDatepicker(a[0]);return false})}},_autoSize:function(a){if(this._get(a,"autoSize")&&!a.inline){var d=new Date(2009,11,20),h=this._get(a,"dateFormat");if(h.match(/[DM]/)){var i=function(j){for(var n=0,q=0,l=0;ln){n=j[l].length;q=l}return q};d.setMonth(i(this._get(a, +h.match(/MM/)?"monthNames":"monthNamesShort")));d.setDate(i(this._get(a,h.match(/DD/)?"dayNames":"dayNamesShort"))+20-d.getDay())}a.input.attr("size",this._formatDate(a,d).length)}},_inlineDatepicker:function(a,d){var h=b(a);if(!h.hasClass(this.markerClassName)){h.addClass(this.markerClassName).append(d.dpDiv).bind("setData.datepicker",function(i,j,n){d.settings[j]=n}).bind("getData.datepicker",function(i,j){return this._get(d,j)});b.data(a,"datepicker",d);this._setDate(d,this._getDefaultDate(d), +true);this._updateDatepicker(d);this._updateAlternate(d)}},_dialogDatepicker:function(a,d,h,i,j){a=this._dialogInst;if(!a){this.uuid+=1;this._dialogInput=b('');this._dialogInput.keydown(this._doKeyDown);b("body").append(this._dialogInput);a=this._dialogInst=this._newInst(this._dialogInput,false);a.settings={};b.data(this._dialogInput[0],"datepicker",a)}g(a.settings,i||{});d=d&&d.constructor== +Date?this._formatDate(a,d):d;this._dialogInput.val(d);this._pos=j?j.length?j:[j.pageX,j.pageY]:null;if(!this._pos)this._pos=[document.documentElement.clientWidth/2-100+(document.documentElement.scrollLeft||document.body.scrollLeft),document.documentElement.clientHeight/2-150+(document.documentElement.scrollTop||document.body.scrollTop)];this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px");a.settings.onSelect=h;this._inDialog=true;this.dpDiv.addClass(this._dialogClass);this._showDatepicker(this._dialogInput[0]); +b.blockUI&&b.blockUI(this.dpDiv);b.data(this._dialogInput[0],"datepicker",a);return this},_destroyDatepicker:function(a){var d=b(a),h=b.data(a,"datepicker");if(d.hasClass(this.markerClassName)){var i=a.nodeName.toLowerCase();b.removeData(a,"datepicker");if(i=="input"){h.append.remove();h.trigger.remove();d.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)}else if(i=="div"||i=="span")d.removeClass(this.markerClassName).empty()}}, +_enableDatepicker:function(a){var d=b(a),h=b.data(a,"datepicker");if(d.hasClass(this.markerClassName)){var i=a.nodeName.toLowerCase();if(i=="input"){a.disabled=false;h.trigger.filter("button").each(function(){this.disabled=false}).end().filter("img").css({opacity:"1.0",cursor:""})}else if(i=="div"||i=="span")d.children("."+this._inlineClass).children().removeClass("ui-state-disabled");this._disabledInputs=b.map(this._disabledInputs,function(j){return j==a?null:j})}},_disableDatepicker:function(a){var d= +b(a),h=b.data(a,"datepicker");if(d.hasClass(this.markerClassName)){var i=a.nodeName.toLowerCase();if(i=="input"){a.disabled=true;h.trigger.filter("button").each(function(){this.disabled=true}).end().filter("img").css({opacity:"0.5",cursor:"default"})}else if(i=="div"||i=="span")d.children("."+this._inlineClass).children().addClass("ui-state-disabled");this._disabledInputs=b.map(this._disabledInputs,function(j){return j==a?null:j});this._disabledInputs[this._disabledInputs.length]=a}},_isDisabledDatepicker:function(a){if(!a)return false; +for(var d=0;d-1}},_doKeyUp:function(a){a=b.datepicker._getInst(a.target);if(a.input.val()!=a.lastVal)try{if(b.datepicker.parseDate(b.datepicker._get(a,"dateFormat"),a.input?a.input.val():null,b.datepicker._getFormatConfig(a))){b.datepicker._setDateFromField(a);b.datepicker._updateAlternate(a);b.datepicker._updateDatepicker(a)}}catch(d){b.datepicker.log(d)}return true},_showDatepicker:function(a){a=a.target|| +a;if(a.nodeName.toLowerCase()!="input")a=b("input",a.parentNode)[0];if(!(b.datepicker._isDisabledDatepicker(a)||b.datepicker._lastInput==a)){var d=b.datepicker._getInst(a);b.datepicker._curInst&&b.datepicker._curInst!=d&&b.datepicker._curInst.dpDiv.stop(true,true);var h=b.datepicker._get(d,"beforeShow");g(d.settings,h?h.apply(a,[a,d]):{});d.lastVal=null;b.datepicker._lastInput=a;b.datepicker._setDateFromField(d);if(b.datepicker._inDialog)a.value="";if(!b.datepicker._pos){b.datepicker._pos=b.datepicker._findPos(a); +b.datepicker._pos[1]+=a.offsetHeight}var i=false;b(a).parents().each(function(){i|=b(this).css("position")=="fixed";return!i});if(i&&b.browser.opera){b.datepicker._pos[0]-=document.documentElement.scrollLeft;b.datepicker._pos[1]-=document.documentElement.scrollTop}h={left:b.datepicker._pos[0],top:b.datepicker._pos[1]};b.datepicker._pos=null;d.dpDiv.css({position:"absolute",display:"block",top:"-1000px"});b.datepicker._updateDatepicker(d);h=b.datepicker._checkOffset(d,h,i);d.dpDiv.css({position:b.datepicker._inDialog&& +b.blockUI?"static":i?"fixed":"absolute",display:"none",left:h.left+"px",top:h.top+"px"});if(!d.inline){h=b.datepicker._get(d,"showAnim");var j=b.datepicker._get(d,"duration"),n=function(){b.datepicker._datepickerShowing=true;var q=b.datepicker._getBorders(d.dpDiv);d.dpDiv.find("iframe.ui-datepicker-cover").css({left:-q[0],top:-q[1],width:d.dpDiv.outerWidth(),height:d.dpDiv.outerHeight()})};d.dpDiv.zIndex(b(a).zIndex()+1);b.effects&&b.effects[h]?d.dpDiv.show(h,b.datepicker._get(d,"showOptions"),j, +n):d.dpDiv[h||"show"](h?j:null,n);if(!h||!j)n();d.input.is(":visible")&&!d.input.is(":disabled")&&d.input.focus();b.datepicker._curInst=d}}},_updateDatepicker:function(a){var d=this,h=b.datepicker._getBorders(a.dpDiv);a.dpDiv.empty().append(this._generateHTML(a)).find("iframe.ui-datepicker-cover").css({left:-h[0],top:-h[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()}).end().find("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a").bind("mouseout",function(){b(this).removeClass("ui-state-hover"); +this.className.indexOf("ui-datepicker-prev")!=-1&&b(this).removeClass("ui-datepicker-prev-hover");this.className.indexOf("ui-datepicker-next")!=-1&&b(this).removeClass("ui-datepicker-next-hover")}).bind("mouseover",function(){if(!d._isDisabledDatepicker(a.inline?a.dpDiv.parent()[0]:a.input[0])){b(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");b(this).addClass("ui-state-hover");this.className.indexOf("ui-datepicker-prev")!=-1&&b(this).addClass("ui-datepicker-prev-hover"); +this.className.indexOf("ui-datepicker-next")!=-1&&b(this).addClass("ui-datepicker-next-hover")}}).end().find("."+this._dayOverClass+" a").trigger("mouseover").end();h=this._getNumberOfMonths(a);var i=h[1];i>1?a.dpDiv.addClass("ui-datepicker-multi-"+i).css("width",17*i+"em"):a.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");a.dpDiv[(h[0]!=1||h[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi");a.dpDiv[(this._get(a,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl"); +a==b.datepicker._curInst&&b.datepicker._datepickerShowing&&a.input&&a.input.is(":visible")&&!a.input.is(":disabled")&&a.input.focus()},_getBorders:function(a){var d=function(h){return{thin:1,medium:2,thick:3}[h]||h};return[parseFloat(d(a.css("border-left-width"))),parseFloat(d(a.css("border-top-width")))]},_checkOffset:function(a,d,h){var i=a.dpDiv.outerWidth(),j=a.dpDiv.outerHeight(),n=a.input?a.input.outerWidth():0,q=a.input?a.input.outerHeight():0,l=document.documentElement.clientWidth+b(document).scrollLeft(), +k=document.documentElement.clientHeight+b(document).scrollTop();d.left-=this._get(a,"isRTL")?i-n:0;d.left-=h&&d.left==a.input.offset().left?b(document).scrollLeft():0;d.top-=h&&d.top==a.input.offset().top+q?b(document).scrollTop():0;d.left-=Math.min(d.left,d.left+i>l&&l>i?Math.abs(d.left+i-l):0);d.top-=Math.min(d.top,d.top+j>k&&k>j?Math.abs(j+q):0);return d},_findPos:function(a){for(var d=this._get(this._getInst(a),"isRTL");a&&(a.type=="hidden"||a.nodeType!=1);)a=a[d?"previousSibling":"nextSibling"]; +a=b(a).offset();return[a.left,a.top]},_hideDatepicker:function(a){var d=this._curInst;if(!(!d||a&&d!=b.data(a,"datepicker")))if(this._datepickerShowing){a=this._get(d,"showAnim");var h=this._get(d,"duration"),i=function(){b.datepicker._tidyDialog(d);this._curInst=null};b.effects&&b.effects[a]?d.dpDiv.hide(a,b.datepicker._get(d,"showOptions"),h,i):d.dpDiv[a=="slideDown"?"slideUp":a=="fadeIn"?"fadeOut":"hide"](a?h:null,i);a||i();if(a=this._get(d,"onClose"))a.apply(d.input?d.input[0]:null,[d.input?d.input.val(): +"",d]);this._datepickerShowing=false;this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:"absolute",left:"0",top:"-100px"});if(b.blockUI){b.unblockUI();b("body").append(this.dpDiv)}}this._inDialog=false}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(a){if(b.datepicker._curInst){a=b(a.target);a[0].id!=b.datepicker._mainDivId&&a.parents("#"+b.datepicker._mainDivId).length==0&&!a.hasClass(b.datepicker.markerClassName)&& +!a.hasClass(b.datepicker._triggerClass)&&b.datepicker._datepickerShowing&&!(b.datepicker._inDialog&&b.blockUI)&&b.datepicker._hideDatepicker()}},_adjustDate:function(a,d,h){a=b(a);var i=this._getInst(a[0]);if(!this._isDisabledDatepicker(a[0])){this._adjustInstDate(i,d+(h=="M"?this._get(i,"showCurrentAtPos"):0),h);this._updateDatepicker(i)}},_gotoToday:function(a){a=b(a);var d=this._getInst(a[0]);if(this._get(d,"gotoCurrent")&&d.currentDay){d.selectedDay=d.currentDay;d.drawMonth=d.selectedMonth=d.currentMonth; +d.drawYear=d.selectedYear=d.currentYear}else{var h=new Date;d.selectedDay=h.getDate();d.drawMonth=d.selectedMonth=h.getMonth();d.drawYear=d.selectedYear=h.getFullYear()}this._notifyChange(d);this._adjustDate(a)},_selectMonthYear:function(a,d,h){a=b(a);var i=this._getInst(a[0]);i._selectingMonthYear=false;i["selected"+(h=="M"?"Month":"Year")]=i["draw"+(h=="M"?"Month":"Year")]=parseInt(d.options[d.selectedIndex].value,10);this._notifyChange(i);this._adjustDate(a)},_clickMonthYear:function(a){var d= +this._getInst(b(a)[0]);d.input&&d._selectingMonthYear&&setTimeout(function(){d.input.focus()},0);d._selectingMonthYear=!d._selectingMonthYear},_selectDay:function(a,d,h,i){var j=b(a);if(!(b(i).hasClass(this._unselectableClass)||this._isDisabledDatepicker(j[0]))){j=this._getInst(j[0]);j.selectedDay=j.currentDay=b("a",i).html();j.selectedMonth=j.currentMonth=d;j.selectedYear=j.currentYear=h;this._selectDate(a,this._formatDate(j,j.currentDay,j.currentMonth,j.currentYear))}},_clearDate:function(a){a= +b(a);this._getInst(a[0]);this._selectDate(a,"")},_selectDate:function(a,d){a=this._getInst(b(a)[0]);d=d!=null?d:this._formatDate(a);a.input&&a.input.val(d);this._updateAlternate(a);var h=this._get(a,"onSelect");if(h)h.apply(a.input?a.input[0]:null,[d,a]);else a.input&&a.input.trigger("change");if(a.inline)this._updateDatepicker(a);else{this._hideDatepicker();this._lastInput=a.input[0];typeof a.input[0]!="object"&&a.input.focus();this._lastInput=null}},_updateAlternate:function(a){var d=this._get(a, +"altField");if(d){var h=this._get(a,"altFormat")||this._get(a,"dateFormat"),i=this._getDate(a),j=this.formatDate(h,i,this._getFormatConfig(a));b(d).each(function(){b(this).val(j)})}},noWeekends:function(a){a=a.getDay();return[a>0&&a<6,""]},iso8601Week:function(a){a=new Date(a.getTime());a.setDate(a.getDate()+4-(a.getDay()||7));var d=a.getTime();a.setMonth(0);a.setDate(1);return Math.floor(Math.round((d-a)/864E5)/7)+1},parseDate:function(a,d,h){if(a==null||d==null)throw"Invalid arguments";d=typeof d== +"object"?d.toString():d+"";if(d=="")return null;for(var i=(h?h.shortYearCutoff:null)||this._defaults.shortYearCutoff,j=(h?h.dayNamesShort:null)||this._defaults.dayNamesShort,n=(h?h.dayNames:null)||this._defaults.dayNames,q=(h?h.monthNamesShort:null)||this._defaults.monthNamesShort,l=(h?h.monthNames:null)||this._defaults.monthNames,k=h=-1,m=-1,o=-1,p=false,s=function(x){(x=y+1 +-1){k=1;m=o;do{i=this._getDaysInMonth(h,k-1);if(m<=i)break;k++;m-=i}while(1)}B=this._daylightSavingAdjust(new Date(h,k-1,m));if(B.getFullYear()!=h||B.getMonth()+1!=k||B.getDate()!=m)throw"Invalid date";return B},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24* +60*60*1E7,formatDate:function(a,d,h){if(!d)return"";var i=(h?h.dayNamesShort:null)||this._defaults.dayNamesShort,j=(h?h.dayNames:null)||this._defaults.dayNames,n=(h?h.monthNamesShort:null)||this._defaults.monthNamesShort;h=(h?h.monthNames:null)||this._defaults.monthNames;var q=function(s){(s=p+112?a.getHours()+2:0);return a},_setDate:function(a,d,h){var i=!d,j=a.selectedMonth,n=a.selectedYear;d=this._restrictMinMax(a,this._determineDate(a,d,new Date));a.selectedDay=a.currentDay=d.getDate();a.drawMonth=a.selectedMonth=a.currentMonth=d.getMonth();a.drawYear=a.selectedYear=a.currentYear=d.getFullYear();if((j!=a.selectedMonth||n!=a.selectedYear)&&!h)this._notifyChange(a);this._adjustInstDate(a);if(a.input)a.input.val(i? +"":this._formatDate(a))},_getDate:function(a){return!a.currentYear||a.input&&a.input.val()==""?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay))},_generateHTML:function(a){var d=new Date;d=this._daylightSavingAdjust(new Date(d.getFullYear(),d.getMonth(),d.getDate()));var h=this._get(a,"isRTL"),i=this._get(a,"showButtonPanel"),j=this._get(a,"hideIfNoPrevNext"),n=this._get(a,"navigationAsDateFormat"),q=this._getNumberOfMonths(a),l=this._get(a,"showCurrentAtPos"),k= +this._get(a,"stepMonths"),m=q[0]!=1||q[1]!=1,o=this._daylightSavingAdjust(!a.currentDay?new Date(9999,9,9):new Date(a.currentYear,a.currentMonth,a.currentDay)),p=this._getMinMaxDate(a,"min"),s=this._getMinMaxDate(a,"max");l=a.drawMonth-l;var r=a.drawYear;if(l<0){l+=12;r--}if(s){var u=this._daylightSavingAdjust(new Date(s.getFullYear(),s.getMonth()-q[0]*q[1]+1,s.getDate()));for(u=p&&uu;){l--;if(l<0){l=11;r--}}}a.drawMonth=l;a.drawYear=r;u=this._get(a, +"prevText");u=!n?u:this.formatDate(u,this._daylightSavingAdjust(new Date(r,l-k,1)),this._getFormatConfig(a));u=this._canAdjustMonth(a,-1,r,l)?''+u+"":j?"":''+ +u+"";var v=this._get(a,"nextText");v=!n?v:this.formatDate(v,this._daylightSavingAdjust(new Date(r,l+k,1)),this._getFormatConfig(a));j=this._canAdjustMonth(a,+1,r,l)?''+v+"":j?"":''+v+"";k=this._get(a,"currentText");v=this._get(a,"gotoCurrent")&&a.currentDay?o:d;k=!n?k:this.formatDate(k,v,this._getFormatConfig(a));n=!a.inline?'":"";i=i?'
    '+(h?n:"")+(this._isInRange(a,v)?'":"")+(h?"":n)+"
    ":"";n=parseInt(this._get(a,"firstDay"),10);n=isNaN(n)?0:n;k=this._get(a,"showWeek");v=this._get(a,"dayNames");this._get(a,"dayNamesShort");var w=this._get(a,"dayNamesMin"),y=this._get(a,"monthNames"),B=this._get(a,"monthNamesShort"),x=this._get(a,"beforeShowDay"),C=this._get(a,"showOtherMonths"),J=this._get(a,"selectOtherMonths");this._get(a,"calculateWeek");for(var M=this._getDefaultDate(a),K="",G=0;G1)switch(H){case 0:D+=" ui-datepicker-group-first";A=" ui-corner-"+(h?"right":"left");break;case q[1]-1:D+=" ui-datepicker-group-last";A=" ui-corner-"+(h?"left":"right");break;default:D+=" ui-datepicker-group-middle";A="";break}D+='">'}D+='
    '+(/all|left/.test(A)&&G==0?h? +j:u:"")+(/all|right/.test(A)&&G==0?h?u:j:"")+this._generateMonthYearHeader(a,l,r,p,s,G>0||H>0,y,B)+'
    ';var E=k?'":"";for(A=0;A<7;A++){var z=(A+n)%7;E+="=5?' class="ui-datepicker-week-end"':"")+'>'+w[z]+""}D+=E+"";E=this._getDaysInMonth(r,l);if(r==a.selectedYear&&l==a.selectedMonth)a.selectedDay=Math.min(a.selectedDay, +E);A=(this._getFirstDayOfMonth(r,l)-n+7)%7;E=m?6:Math.ceil((A+E)/7);z=this._daylightSavingAdjust(new Date(r,l,1-A));for(var P=0;P";var Q=!k?"":'";for(A=0;A<7;A++){var I=x?x.apply(a.input?a.input[0]:null,[z]):[true,""],F=z.getMonth()!=l,L=F&&!J||!I[0]||p&&zs;Q+='";z.setDate(z.getDate()+1);z=this._daylightSavingAdjust(z)}D+=Q+""}l++;if(l>11){l=0;r++}D+="
    '+this._get(a,"weekHeader")+"
    '+this._get(a,"calculateWeek")(z)+""+(F&&!C?" ":L?''+z.getDate()+ +"":''+z.getDate()+"")+"
    "+(m?""+(q[0]>0&&H==q[1]-1?'
    ':""):"");N+=D}K+=N}K+=i+(b.browser.msie&&parseInt(b.browser.version,10)<7&&!a.inline?'': +"");a._keyEvent=false;return K},_generateMonthYearHeader:function(a,d,h,i,j,n,q,l){var k=this._get(a,"changeMonth"),m=this._get(a,"changeYear"),o=this._get(a,"showMonthAfterYear"),p='
    ',s="";if(n||!k)s+=''+q[d]+"";else{q=i&&i.getFullYear()==h;var r=j&&j.getFullYear()==h;s+='"}o||(p+=s+(n||!(k&&m)?" ":""));if(n||!m)p+=''+h+"";else{l=this._get(a,"yearRange").split(":");var v=(new Date).getFullYear();q=function(w){w=w.match(/c[+-].*/)?h+parseInt(w.substring(1),10):w.match(/[+-].*/)?v+parseInt(w,10):parseInt(w,10);return isNaN(w)?v:w};d=q(l[0]);l=Math.max(d, +q(l[1]||""));d=i?Math.max(d,i.getFullYear()):d;l=j?Math.min(l,j.getFullYear()):l;for(p+='"}p+=this._get(a,"yearSuffix");if(o)p+=(n||!(k&&m)?" ":"")+s;p+="
    ";return p},_adjustInstDate:function(a,d,h){var i= +a.drawYear+(h=="Y"?d:0),j=a.drawMonth+(h=="M"?d:0);d=Math.min(a.selectedDay,this._getDaysInMonth(i,j))+(h=="D"?d:0);i=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(i,j,d)));a.selectedDay=i.getDate();a.drawMonth=a.selectedMonth=i.getMonth();a.drawYear=a.selectedYear=i.getFullYear();if(h=="M"||h=="Y")this._notifyChange(a)},_restrictMinMax:function(a,d){var h=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");d=h&&da?a:d},_notifyChange:function(a){var d=this._get(a, +"onChangeMonthYear");if(d)d.apply(a.input?a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){a=this._get(a,"numberOfMonths");return a==null?[1,1]:typeof a=="number"?[1,a]:a},_getMinMaxDate:function(a,d){return this._determineDate(a,this._get(a,d+"Date"),null)},_getDaysInMonth:function(a,d){return 32-(new Date(a,d,32)).getDate()},_getFirstDayOfMonth:function(a,d){return(new Date(a,d,1)).getDay()},_canAdjustMonth:function(a,d,h,i){var j=this._getNumberOfMonths(a); +h=this._daylightSavingAdjust(new Date(h,i+(d<0?d:j[0]*j[1]),1));d<0&&h.setDate(this._getDaysInMonth(h.getFullYear(),h.getMonth()));return this._isInRange(a,h)},_isInRange:function(a,d){var h=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");return(!h||d.getTime()>=h.getTime())&&(!a||d.getTime()<=a.getTime())},_getFormatConfig:function(a){var d=this._get(a,"shortYearCutoff");d=typeof d!="string"?d:(new Date).getFullYear()%100+parseInt(d,10);return{shortYearCutoff:d,dayNamesShort:this._get(a, +"dayNamesShort"),dayNames:this._get(a,"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,d,h,i){if(!d){a.currentDay=a.selectedDay;a.currentMonth=a.selectedMonth;a.currentYear=a.selectedYear}d=d?typeof d=="object"?d:this._daylightSavingAdjust(new Date(i,h,d)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),d,this._getFormatConfig(a))}});b.fn.datepicker= +function(a){if(!b.datepicker.initialized){b(document).mousedown(b.datepicker._checkExternalClick).find("body").append(b.datepicker.dpDiv);b.datepicker.initialized=true}var d=Array.prototype.slice.call(arguments,1);if(typeof a=="string"&&(a=="isDisabled"||a=="getDate"||a=="widget"))return b.datepicker["_"+a+"Datepicker"].apply(b.datepicker,[this[0]].concat(d));if(a=="option"&&arguments.length==2&&typeof arguments[1]=="string")return b.datepicker["_"+a+"Datepicker"].apply(b.datepicker,[this[0]].concat(d)); +return this.each(function(){typeof a=="string"?b.datepicker["_"+a+"Datepicker"].apply(b.datepicker,[this].concat(d)):b.datepicker._attachDatepicker(this,a)})};b.datepicker=new f;b.datepicker.initialized=false;b.datepicker.uuid=(new Date).getTime();b.datepicker.version="1.8.6";window["DP_jQuery_"+e]=b})(jQuery); +(function(b,c){var f={buttons:true,height:true,maxHeight:true,maxWidth:true,minHeight:true,minWidth:true,width:true},g={maxHeight:true,maxWidth:true,minHeight:true,minWidth:true};b.widget("ui.dialog",{options:{autoOpen:true,buttons:{},closeOnEscape:true,closeText:"close",dialogClass:"",draggable:true,hide:null,height:"auto",maxHeight:false,maxWidth:false,minHeight:150,minWidth:150,modal:false,position:{my:"center",at:"center",of:window,collision:"fit",using:function(e){var a=b(this).css(e).offset().top; +a<0&&b(this).css("top",e.top-a)}},resizable:true,show:null,stack:true,title:"",width:300,zIndex:1E3},_create:function(){this.originalTitle=this.element.attr("title");if(typeof this.originalTitle!=="string")this.originalTitle="";this.options.title=this.options.title||this.originalTitle;var e=this,a=e.options,d=a.title||" ",h=b.ui.dialog.getTitleId(e.element),i=(e.uiDialog=b("
    ")).appendTo(document.body).hide().addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+a.dialogClass).css({zIndex:a.zIndex}).attr("tabIndex", +-1).css("outline",0).keydown(function(q){if(a.closeOnEscape&&q.keyCode&&q.keyCode===b.ui.keyCode.ESCAPE){e.close(q);q.preventDefault()}}).attr({role:"dialog","aria-labelledby":h}).mousedown(function(q){e.moveToTop(false,q)});e.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(i);var j=(e.uiDialogTitlebar=b("
    ")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(i),n=b('').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role", +"button").hover(function(){n.addClass("ui-state-hover")},function(){n.removeClass("ui-state-hover")}).focus(function(){n.addClass("ui-state-focus")}).blur(function(){n.removeClass("ui-state-focus")}).click(function(q){e.close(q);return false}).appendTo(j);(e.uiDialogTitlebarCloseText=b("")).addClass("ui-icon ui-icon-closethick").text(a.closeText).appendTo(n);b("").addClass("ui-dialog-title").attr("id",h).html(d).prependTo(j);if(b.isFunction(a.beforeclose)&&!b.isFunction(a.beforeClose))a.beforeClose= +a.beforeclose;j.find("*").add(j).disableSelection();a.draggable&&b.fn.draggable&&e._makeDraggable();a.resizable&&b.fn.resizable&&e._makeResizable();e._createButtons(a.buttons);e._isOpen=false;b.fn.bgiframe&&i.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var e=this;e.overlay&&e.overlay.destroy();e.uiDialog.hide();e.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body");e.uiDialog.remove();e.originalTitle&& +e.element.attr("title",e.originalTitle);return e},widget:function(){return this.uiDialog},close:function(e){var a=this,d;if(false!==a._trigger("beforeClose",e)){a.overlay&&a.overlay.destroy();a.uiDialog.unbind("keypress.ui-dialog");a._isOpen=false;if(a.options.hide)a.uiDialog.hide(a.options.hide,function(){a._trigger("close",e)});else{a.uiDialog.hide();a._trigger("close",e)}b.ui.dialog.overlay.resize();if(a.options.modal){d=0;b(".ui-dialog").each(function(){if(this!==a.uiDialog[0])d=Math.max(d,b(this).css("z-index"))}); +b.ui.dialog.maxZ=d}return a}},isOpen:function(){return this._isOpen},moveToTop:function(e,a){var d=this,h=d.options;if(h.modal&&!e||!h.stack&&!h.modal)return d._trigger("focus",a);if(h.zIndex>b.ui.dialog.maxZ)b.ui.dialog.maxZ=h.zIndex;if(d.overlay){b.ui.dialog.maxZ+=1;d.overlay.$el.css("z-index",b.ui.dialog.overlay.maxZ=b.ui.dialog.maxZ)}e={scrollTop:d.element.attr("scrollTop"),scrollLeft:d.element.attr("scrollLeft")};b.ui.dialog.maxZ+=1;d.uiDialog.css("z-index",b.ui.dialog.maxZ);d.element.attr(e); +d._trigger("focus",a);return d},open:function(){if(!this._isOpen){var e=this,a=e.options,d=e.uiDialog;e.overlay=a.modal?new b.ui.dialog.overlay(e):null;e._size();e._position(a.position);d.show(a.show);e.moveToTop(true);a.modal&&d.bind("keypress.ui-dialog",function(h){if(h.keyCode===b.ui.keyCode.TAB){var i=b(":tabbable",this),j=i.filter(":first");i=i.filter(":last");if(h.target===i[0]&&!h.shiftKey){j.focus(1);return false}else if(h.target===j[0]&&h.shiftKey){i.focus(1);return false}}});b(e.element.find(":tabbable").get().concat(d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus(); +e._isOpen=true;e._trigger("open");return e}},_createButtons:function(e){var a=this,d=false,h=b("
    ").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),i=b("
    ").addClass("ui-dialog-buttonset").appendTo(h);a.uiDialog.find(".ui-dialog-buttonpane").remove();typeof e==="object"&&e!==null&&b.each(e,function(){return!(d=true)});if(d){b.each(e,function(j,n){n=b.isFunction(n)?{click:n,text:j}:n;j=b('').attr(n,true).unbind("click").click(function(){n.click.apply(a.element[0], +arguments)}).appendTo(i);b.fn.button&&j.button()});h.appendTo(a.uiDialog)}},_makeDraggable:function(){function e(j){return{position:j.position,offset:j.offset}}var a=this,d=a.options,h=b(document),i;a.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(j,n){i=d.height==="auto"?"auto":b(this).height();b(this).height(b(this).height()).addClass("ui-dialog-dragging");a._trigger("dragStart",j,e(n))},drag:function(j, +n){a._trigger("drag",j,e(n))},stop:function(j,n){d.position=[n.position.left-h.scrollLeft(),n.position.top-h.scrollTop()];b(this).removeClass("ui-dialog-dragging").height(i);a._trigger("dragStop",j,e(n));b.ui.dialog.overlay.resize()}})},_makeResizable:function(e){function a(j){return{originalPosition:j.originalPosition,originalSize:j.originalSize,position:j.position,size:j.size}}e=e===c?this.options.resizable:e;var d=this,h=d.options,i=d.uiDialog.css("position");e=typeof e==="string"?e:"n,e,s,w,se,sw,ne,nw"; +d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:h.maxWidth,maxHeight:h.maxHeight,minWidth:h.minWidth,minHeight:d._minHeight(),handles:e,start:function(j,n){b(this).addClass("ui-dialog-resizing");d._trigger("resizeStart",j,a(n))},resize:function(j,n){d._trigger("resize",j,a(n))},stop:function(j,n){b(this).removeClass("ui-dialog-resizing");h.height=b(this).height();h.width=b(this).width();d._trigger("resizeStop",j,a(n));b.ui.dialog.overlay.resize()}}).css("position", +i).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var e=this.options;return e.height==="auto"?e.minHeight:Math.min(e.minHeight,e.height)},_position:function(e){var a=[],d=[0,0],h;if(e){if(typeof e==="string"||typeof e==="object"&&"0"in e){a=e.split?e.split(" "):[e[0],e[1]];if(a.length===1)a[1]=a[0];b.each(["left","top"],function(i,j){if(+a[i]===a[i]){d[i]=a[i];a[i]=j}});e={my:a.join(" "),at:a.join(" "),offset:d.join(" ")}}e=b.extend({},b.ui.dialog.prototype.options.position, +e)}else e=b.ui.dialog.prototype.options.position;(h=this.uiDialog.is(":visible"))||this.uiDialog.show();this.uiDialog.css({top:0,left:0}).position(e);h||this.uiDialog.hide()},_setOptions:function(e){var a=this,d={},h=false;b.each(e,function(i,j){a._setOption(i,j);if(i in f)h=true;if(i in g)d[i]=j});h&&this._size();this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",d)},_setOption:function(e,a){var d=this,h=d.uiDialog;switch(e){case "beforeclose":e="beforeClose";break;case "buttons":d._createButtons(a); +break;case "closeText":d.uiDialogTitlebarCloseText.text(""+a);break;case "dialogClass":h.removeClass(d.options.dialogClass).addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+a);break;case "disabled":a?h.addClass("ui-dialog-disabled"):h.removeClass("ui-dialog-disabled");break;case "draggable":var i=h.is(":data(draggable)");i&&!a&&h.draggable("destroy");!i&&a&&d._makeDraggable();break;case "position":d._position(a);break;case "resizable":(i=h.is(":data(resizable)"))&&!a&&h.resizable("destroy"); +i&&typeof a==="string"&&h.resizable("option","handles",a);!i&&a!==false&&d._makeResizable(a);break;case "title":b(".ui-dialog-title",d.uiDialogTitlebar).html(""+(a||" "));break}b.Widget.prototype._setOption.apply(d,arguments)},_size:function(){var e=this.options,a,d;this.element.show().css({width:"auto",minHeight:0,height:0});if(e.minWidth>e.width)e.width=e.minWidth;a=this.uiDialog.css({height:"auto",width:e.width}).height();d=Math.max(0,e.minHeight-a);if(e.height==="auto")if(b.support.minHeight)this.element.css({minHeight:d, +height:"auto"});else{this.uiDialog.show();e=this.element.css("height","auto").height();this.uiDialog.hide();this.element.height(Math.max(e,d))}else this.element.height(Math.max(e.height-a,0));this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())}});b.extend(b.ui.dialog,{version:"1.8.6",uuid:0,maxZ:0,getTitleId:function(e){e=e.attr("id");if(!e){this.uuid+=1;e=this.uuid}return"ui-dialog-title-"+e},overlay:function(e){this.$el=b.ui.dialog.overlay.create(e)}}); +b.extend(b.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:b.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(e){return e+".dialog-overlay"}).join(" "),create:function(e){if(this.instances.length===0){setTimeout(function(){b.ui.dialog.overlay.instances.length&&b(document).bind(b.ui.dialog.overlay.events,function(d){if(b(d.target).zIndex()").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(),height:this.height()});b.fn.bgiframe&&a.bgiframe();this.instances.push(a);return a},destroy:function(e){this.oldInstances.push(this.instances.splice(b.inArray(e,this.instances),1)[0]);this.instances.length===0&&b([document,window]).unbind(".dialog-overlay"); +e.remove();var a=0;b.each(this.instances,function(){a=Math.max(a,this.css("z-index"))});this.maxZ=a},height:function(){var e,a;if(b.browser.msie&&b.browser.version<7){e=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);a=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);return e0? +a.left-h:Math.max(a.left-d.collisionPosition.left,a.left)},top:function(a,d){var h=b(window);h=d.collisionPosition.top+d.collisionHeight-h.height()-h.scrollTop();a.top=h>0?a.top-h:Math.max(a.top-d.collisionPosition.top,a.top)}},flip:{left:function(a,d){if(d.at[0]!=="center"){var h=b(window);h=d.collisionPosition.left+d.collisionWidth-h.width()-h.scrollLeft();var i=d.my[0]==="left"?-d.elemWidth:d.my[0]==="right"?d.elemWidth:0,j=d.at[0]==="left"?d.targetWidth:-d.targetWidth,n=-2*d.offset[0];a.left+= +d.collisionPosition.left<0?i+j+n:h>0?i+j+n:0}},top:function(a,d){if(d.at[1]!=="center"){var h=b(window);h=d.collisionPosition.top+d.collisionHeight-h.height()-h.scrollTop();var i=d.my[1]==="top"?-d.elemHeight:d.my[1]==="bottom"?d.elemHeight:0,j=d.at[1]==="top"?d.targetHeight:-d.targetHeight,n=-2*d.offset[1];a.top+=d.collisionPosition.top<0?i+j+n:h>0?i+j+n:0}}}};if(!b.offset.setOffset){b.offset.setOffset=function(a,d){if(/static/.test(b.curCSS(a,"position")))a.style.position="relative";var h=b(a), +i=h.offset(),j=parseInt(b.curCSS(a,"top",true),10)||0,n=parseInt(b.curCSS(a,"left",true),10)||0;i={top:d.top-i.top+j,left:d.left-i.left+n};"using"in d?d.using.call(a,i):h.css(i)};b.fn.offset=function(a){var d=this[0];if(!d||!d.ownerDocument)return null;if(a)return this.each(function(){b.offset.setOffset(this,a)});return e.call(this)}}})(jQuery); +(function(b,c){b.widget("ui.progressbar",{options:{value:0},min:0,max:100,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.max,"aria-valuenow":this._value()});this.valueDiv=b("
    ").appendTo(this.element);this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"); +this.valueDiv.remove();b.Widget.prototype.destroy.apply(this,arguments)},value:function(f){if(f===c)return this._value();this._setOption("value",f);return this},_setOption:function(f,g){if(f==="value"){this.options.value=g;this._refreshValue();this._trigger("change");this._value()===this.max&&this._trigger("complete")}b.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var f=this.options.value;if(typeof f!=="number")f=0;return Math.min(this.max,Math.max(this.min,f))},_refreshValue:function(){var f= +this.value();this.valueDiv.toggleClass("ui-corner-right",f===this.max).width(f+"%");this.element.attr("aria-valuenow",f)}});b.extend(b.ui.progressbar,{version:"1.8.6"})})(jQuery); +(function(b){b.widget("ui.slider",b.ui.mouse,{widgetEventPrefix:"slide",options:{animate:false,distance:0,max:100,min:0,orientation:"horizontal",range:false,step:1,value:0,values:null},_create:function(){var c=this,f=this.options;this._mouseSliding=this._keySliding=false;this._animateOff=true;this._handleIndex=null;this._detectOrientation();this._mouseInit();this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget ui-widget-content ui-corner-all");f.disabled&&this.element.addClass("ui-slider-disabled ui-disabled"); +this.range=b([]);if(f.range){if(f.range===true){this.range=b("
    ");if(!f.values)f.values=[this._valueMin(),this._valueMin()];if(f.values.length&&f.values.length!==2)f.values=[f.values[0],f.values[0]]}else this.range=b("
    ");this.range.appendTo(this.element).addClass("ui-slider-range");if(f.range==="min"||f.range==="max")this.range.addClass("ui-slider-range-"+f.range);this.range.addClass("ui-widget-header")}b(".ui-slider-handle",this.element).length===0&&b("").appendTo(this.element).addClass("ui-slider-handle"); +if(f.values&&f.values.length)for(;b(".ui-slider-handle",this.element).length").appendTo(this.element).addClass("ui-slider-handle");this.handles=b(".ui-slider-handle",this.element).addClass("ui-state-default ui-corner-all");this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(g){g.preventDefault()}).hover(function(){f.disabled||b(this).addClass("ui-state-hover")},function(){b(this).removeClass("ui-state-hover")}).focus(function(){if(f.disabled)b(this).blur(); +else{b(".ui-slider .ui-state-focus").removeClass("ui-state-focus");b(this).addClass("ui-state-focus")}}).blur(function(){b(this).removeClass("ui-state-focus")});this.handles.each(function(g){b(this).data("index.ui-slider-handle",g)});this.handles.keydown(function(g){var e=true,a=b(this).data("index.ui-slider-handle"),d,h,i;if(!c.options.disabled){switch(g.keyCode){case b.ui.keyCode.HOME:case b.ui.keyCode.END:case b.ui.keyCode.PAGE_UP:case b.ui.keyCode.PAGE_DOWN:case b.ui.keyCode.UP:case b.ui.keyCode.RIGHT:case b.ui.keyCode.DOWN:case b.ui.keyCode.LEFT:e= +false;if(!c._keySliding){c._keySliding=true;b(this).addClass("ui-state-active");d=c._start(g,a);if(d===false)return}break}i=c.options.step;d=c.options.values&&c.options.values.length?(h=c.values(a)):(h=c.value());switch(g.keyCode){case b.ui.keyCode.HOME:h=c._valueMin();break;case b.ui.keyCode.END:h=c._valueMax();break;case b.ui.keyCode.PAGE_UP:h=c._trimAlignValue(d+(c._valueMax()-c._valueMin())/5);break;case b.ui.keyCode.PAGE_DOWN:h=c._trimAlignValue(d-(c._valueMax()-c._valueMin())/5);break;case b.ui.keyCode.UP:case b.ui.keyCode.RIGHT:if(d=== +c._valueMax())return;h=c._trimAlignValue(d+i);break;case b.ui.keyCode.DOWN:case b.ui.keyCode.LEFT:if(d===c._valueMin())return;h=c._trimAlignValue(d-i);break}c._slide(g,a,h);return e}}).keyup(function(g){var e=b(this).data("index.ui-slider-handle");if(c._keySliding){c._keySliding=false;c._stop(g,e);c._change(g,e);b(this).removeClass("ui-state-active")}});this._refreshValue();this._animateOff=false},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider"); +this._mouseDestroy();return this},_mouseCapture:function(c){var f=this.options,g,e,a,d,h;if(f.disabled)return false;this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();g=this._normValueFromMouse({x:c.pageX,y:c.pageY});e=this._valueMax()-this._valueMin()+1;d=this;this.handles.each(function(i){var j=Math.abs(g-d.values(i));if(e>j){e=j;a=b(this);h=i}});if(f.range===true&&this.values(1)===f.min){h+=1;a=b(this.handles[h])}if(this._start(c, +h)===false)return false;this._mouseSliding=true;d._handleIndex=h;a.addClass("ui-state-active").focus();f=a.offset();this._clickOffset=!b(c.target).parents().andSelf().is(".ui-slider-handle")?{left:0,top:0}:{left:c.pageX-f.left-a.width()/2,top:c.pageY-f.top-a.height()/2-(parseInt(a.css("borderTopWidth"),10)||0)-(parseInt(a.css("borderBottomWidth"),10)||0)+(parseInt(a.css("marginTop"),10)||0)};this._slide(c,h,g);return this._animateOff=true},_mouseStart:function(){return true},_mouseDrag:function(c){var f= +this._normValueFromMouse({x:c.pageX,y:c.pageY});this._slide(c,this._handleIndex,f);return false},_mouseStop:function(c){this.handles.removeClass("ui-state-active");this._mouseSliding=false;this._stop(c,this._handleIndex);this._change(c,this._handleIndex);this._clickOffset=this._handleIndex=null;return this._animateOff=false},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(c){var f;if(this.orientation==="horizontal"){f= +this.elementSize.width;c=c.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{f=this.elementSize.height;c=c.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}f=c/f;if(f>1)f=1;if(f<0)f=0;if(this.orientation==="vertical")f=1-f;c=this._valueMax()-this._valueMin();return this._trimAlignValue(this._valueMin()+f*c)},_start:function(c,f){var g={handle:this.handles[f],value:this.value()};if(this.options.values&&this.options.values.length){g.value=this.values(f); +g.values=this.values()}return this._trigger("start",c,g)},_slide:function(c,f,g){var e;if(this.options.values&&this.options.values.length){e=this.values(f?0:1);if(this.options.values.length===2&&this.options.range===true&&(f===0&&g>e||f===1&&g1){this.options.values[c]=this._trimAlignValue(f);this._refreshValue();this._change(null,c)}if(arguments.length)if(b.isArray(arguments[0])){g=this.options.values;e=arguments[0];for(a=0;athis._valueMax())return this._valueMax();var f=this.options.step>0?this.options.step:1,g=c%f;c=c-g;if(Math.abs(g)*2>=f)c+=g>0?f:-f;return parseFloat(c.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var c= +this.options.range,f=this.options,g=this,e=!this._animateOff?f.animate:false,a,d={},h,i,j,n;if(this.options.values&&this.options.values.length)this.handles.each(function(q){a=(g.values(q)-g._valueMin())/(g._valueMax()-g._valueMin())*100;d[g.orientation==="horizontal"?"left":"bottom"]=a+"%";b(this).stop(1,1)[e?"animate":"css"](d,f.animate);if(g.options.range===true)if(g.orientation==="horizontal"){if(q===0)g.range.stop(1,1)[e?"animate":"css"]({left:a+"%"},f.animate);if(q===1)g.range[e?"animate":"css"]({width:a- +h+"%"},{queue:false,duration:f.animate})}else{if(q===0)g.range.stop(1,1)[e?"animate":"css"]({bottom:a+"%"},f.animate);if(q===1)g.range[e?"animate":"css"]({height:a-h+"%"},{queue:false,duration:f.animate})}h=a});else{i=this.value();j=this._valueMin();n=this._valueMax();a=n!==j?(i-j)/(n-j)*100:0;d[g.orientation==="horizontal"?"left":"bottom"]=a+"%";this.handle.stop(1,1)[e?"animate":"css"](d,f.animate);if(c==="min"&&this.orientation==="horizontal")this.range.stop(1,1)[e?"animate":"css"]({width:a+"%"}, +f.animate);if(c==="max"&&this.orientation==="horizontal")this.range[e?"animate":"css"]({width:100-a+"%"},{queue:false,duration:f.animate});if(c==="min"&&this.orientation==="vertical")this.range.stop(1,1)[e?"animate":"css"]({height:a+"%"},f.animate);if(c==="max"&&this.orientation==="vertical")this.range[e?"animate":"css"]({height:100-a+"%"},{queue:false,duration:f.animate})}}});b.extend(b.ui.slider,{version:"1.8.6"})})(jQuery); +(function(b,c){function f(){return++e}function g(){return++a}var e=0,a=0;b.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:false,cookie:null,collapsible:false,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"
    ",remove:null,select:null,show:null,spinner:"Loading…",tabTemplate:"
  • #{label}
  • "},_create:function(){this._tabify(true)},_setOption:function(d,h){if(d=="selected")this.options.collapsible&& +h==this.options.selected||this.select(h);else{this.options[d]=h;this._tabify()}},_tabId:function(d){return d.title&&d.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF-]/g,"")||this.options.idPrefix+f()},_sanitizeSelector:function(d){return d.replace(/:/g,"\\:")},_cookie:function(){var d=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+g());return b.cookie.apply(null,[d].concat(b.makeArray(arguments)))},_ui:function(d,h){return{tab:d,panel:h,index:this.anchors.index(d)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var d= +b(this);d.html(d.data("label.tabs")).removeData("label.tabs")})},_tabify:function(d){function h(r,u){r.css("display","");!b.support.opacity&&u.opacity&&r[0].style.removeAttribute("filter")}var i=this,j=this.options,n=/^#.+/;this.list=this.element.find("ol,ul").eq(0);this.lis=b(" > li:has(a[href])",this.list);this.anchors=this.lis.map(function(){return b("a",this)[0]});this.panels=b([]);this.anchors.each(function(r,u){var v=b(u).attr("href"),w=v.split("#")[0],y;if(w&&(w===location.toString().split("#")[0]|| +(y=b("base")[0])&&w===y.href)){v=u.hash;u.href=v}if(n.test(v))i.panels=i.panels.add(i._sanitizeSelector(v));else if(v&&v!=="#"){b.data(u,"href.tabs",v);b.data(u,"load.tabs",v.replace(/#.*$/,""));v=i._tabId(u);u.href="#"+v;u=b("#"+v);if(!u.length){u=b(j.panelTemplate).attr("id",v).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(i.panels[r-1]||i.list);u.data("destroy.tabs",true)}i.panels=i.panels.add(u)}else j.disabled.push(r)});if(d){this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all"); +this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.lis.addClass("ui-state-default ui-corner-top");this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom");if(j.selected===c){location.hash&&this.anchors.each(function(r,u){if(u.hash==location.hash){j.selected=r;return false}});if(typeof j.selected!=="number"&&j.cookie)j.selected=parseInt(i._cookie(),10);if(typeof j.selected!=="number"&&this.lis.filter(".ui-tabs-selected").length)j.selected= +this.lis.index(this.lis.filter(".ui-tabs-selected"));j.selected=j.selected||(this.lis.length?0:-1)}else if(j.selected===null)j.selected=-1;j.selected=j.selected>=0&&this.anchors[j.selected]||j.selected<0?j.selected:0;j.disabled=b.unique(j.disabled.concat(b.map(this.lis.filter(".ui-state-disabled"),function(r){return i.lis.index(r)}))).sort();b.inArray(j.selected,j.disabled)!=-1&&j.disabled.splice(b.inArray(j.selected,j.disabled),1);this.panels.addClass("ui-tabs-hide");this.lis.removeClass("ui-tabs-selected ui-state-active"); +if(j.selected>=0&&this.anchors.length){b(i._sanitizeSelector(i.anchors[j.selected].hash)).removeClass("ui-tabs-hide");this.lis.eq(j.selected).addClass("ui-tabs-selected ui-state-active");i.element.queue("tabs",function(){i._trigger("show",null,i._ui(i.anchors[j.selected],b(i._sanitizeSelector(i.anchors[j.selected].hash))))});this.load(j.selected)}b(window).bind("unload",function(){i.lis.add(i.anchors).unbind(".tabs");i.lis=i.anchors=i.panels=null})}else j.selected=this.lis.index(this.lis.filter(".ui-tabs-selected")); +this.element[j.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible");j.cookie&&this._cookie(j.selected,j.cookie);d=0;for(var q;q=this.lis[d];d++)b(q)[b.inArray(d,j.disabled)!=-1&&!b(q).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");j.cache===false&&this.anchors.removeData("cache.tabs");this.lis.add(this.anchors).unbind(".tabs");if(j.event!=="mouseover"){var l=function(r,u){u.is(":not(.ui-state-disabled)")&&u.addClass("ui-state-"+r)},k=function(r,u){u.removeClass("ui-state-"+ +r)};this.lis.bind("mouseover.tabs",function(){l("hover",b(this))});this.lis.bind("mouseout.tabs",function(){k("hover",b(this))});this.anchors.bind("focus.tabs",function(){l("focus",b(this).closest("li"))});this.anchors.bind("blur.tabs",function(){k("focus",b(this).closest("li"))})}var m,o;if(j.fx)if(b.isArray(j.fx)){m=j.fx[0];o=j.fx[1]}else m=o=j.fx;var p=o?function(r,u){b(r).closest("li").addClass("ui-tabs-selected ui-state-active");u.hide().removeClass("ui-tabs-hide").animate(o,o.duration||"normal", +function(){h(u,o);i._trigger("show",null,i._ui(r,u[0]))})}:function(r,u){b(r).closest("li").addClass("ui-tabs-selected ui-state-active");u.removeClass("ui-tabs-hide");i._trigger("show",null,i._ui(r,u[0]))},s=m?function(r,u){u.animate(m,m.duration||"normal",function(){i.lis.removeClass("ui-tabs-selected ui-state-active");u.addClass("ui-tabs-hide");h(u,m);i.element.dequeue("tabs")})}:function(r,u){i.lis.removeClass("ui-tabs-selected ui-state-active");u.addClass("ui-tabs-hide");i.element.dequeue("tabs")}; +this.anchors.bind(j.event+".tabs",function(){var r=this,u=b(r).closest("li"),v=i.panels.filter(":not(.ui-tabs-hide)"),w=b(i._sanitizeSelector(r.hash));if(u.hasClass("ui-tabs-selected")&&!j.collapsible||u.hasClass("ui-state-disabled")||u.hasClass("ui-state-processing")||i.panels.filter(":animated").length||i._trigger("select",null,i._ui(this,w[0]))===false){this.blur();return false}j.selected=i.anchors.index(this);i.abort();if(j.collapsible)if(u.hasClass("ui-tabs-selected")){j.selected=-1;j.cookie&& +i._cookie(j.selected,j.cookie);i.element.queue("tabs",function(){s(r,v)}).dequeue("tabs");this.blur();return false}else if(!v.length){j.cookie&&i._cookie(j.selected,j.cookie);i.element.queue("tabs",function(){p(r,w)});i.load(i.anchors.index(this));this.blur();return false}j.cookie&&i._cookie(j.selected,j.cookie);if(w.length){v.length&&i.element.queue("tabs",function(){s(r,v)});i.element.queue("tabs",function(){p(r,w)});i.load(i.anchors.index(this))}else throw"jQuery UI Tabs: Mismatching fragment identifier."; +b.browser.msie&&this.blur()});this.anchors.bind("click.tabs",function(){return false})},_getIndex:function(d){if(typeof d=="string")d=this.anchors.index(this.anchors.filter("[href$="+d+"]"));return d},destroy:function(){var d=this.options;this.abort();this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs");this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.anchors.each(function(){var h= +b.data(this,"href.tabs");if(h)this.href=h;var i=b(this).unbind(".tabs");b.each(["href","load","cache"],function(j,n){i.removeData(n+".tabs")})});this.lis.unbind(".tabs").add(this.panels).each(function(){b.data(this,"destroy.tabs")?b(this).remove():b(this).removeClass("ui-state-default ui-corner-top ui-tabs-selected ui-state-active ui-state-hover ui-state-focus ui-state-disabled ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide")});d.cookie&&this._cookie(null,d.cookie);return this},add:function(d, +h,i){if(i===c)i=this.anchors.length;var j=this,n=this.options;h=b(n.tabTemplate.replace(/#\{href\}/g,d).replace(/#\{label\}/g,h));d=!d.indexOf("#")?d.replace("#",""):this._tabId(b("a",h)[0]);h.addClass("ui-state-default ui-corner-top").data("destroy.tabs",true);var q=b("#"+d);q.length||(q=b(n.panelTemplate).attr("id",d).data("destroy.tabs",true));q.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide");if(i>=this.lis.length){h.appendTo(this.list);q.appendTo(this.list[0].parentNode)}else{h.insertBefore(this.lis[i]); +q.insertBefore(this.panels[i])}n.disabled=b.map(n.disabled,function(l){return l>=i?++l:l});this._tabify();if(this.anchors.length==1){n.selected=0;h.addClass("ui-tabs-selected ui-state-active");q.removeClass("ui-tabs-hide");this.element.queue("tabs",function(){j._trigger("show",null,j._ui(j.anchors[0],j.panels[0]))});this.load(0)}this._trigger("add",null,this._ui(this.anchors[i],this.panels[i]));return this},remove:function(d){d=this._getIndex(d);var h=this.options,i=this.lis.eq(d).remove(),j=this.panels.eq(d).remove(); +if(i.hasClass("ui-tabs-selected")&&this.anchors.length>1)this.select(d+(d+1=d?--n:n});this._tabify();this._trigger("remove",null,this._ui(i.find("a")[0],j[0]));return this},enable:function(d){d=this._getIndex(d);var h=this.options;if(b.inArray(d,h.disabled)!=-1){this.lis.eq(d).removeClass("ui-state-disabled");h.disabled=b.grep(h.disabled,function(i){return i!=d});this._trigger("enable",null, +this._ui(this.anchors[d],this.panels[d]));return this}},disable:function(d){d=this._getIndex(d);var h=this.options;if(d!=h.selected){this.lis.eq(d).addClass("ui-state-disabled");h.disabled.push(d);h.disabled.sort();this._trigger("disable",null,this._ui(this.anchors[d],this.panels[d]))}return this},select:function(d){d=this._getIndex(d);if(d==-1)if(this.options.collapsible&&this.options.selected!=-1)d=this.options.selected;else return this;this.anchors.eq(d).trigger(this.options.event+".tabs");return this}, +load:function(d){d=this._getIndex(d);var h=this,i=this.options,j=this.anchors.eq(d)[0],n=b.data(j,"load.tabs");this.abort();if(!n||this.element.queue("tabs").length!==0&&b.data(j,"cache.tabs"))this.element.dequeue("tabs");else{this.lis.eq(d).addClass("ui-state-processing");if(i.spinner){var q=b("span",j);q.data("label.tabs",q.html()).html(i.spinner)}this.xhr=b.ajax(b.extend({},i.ajaxOptions,{url:n,success:function(l,k){b(h._sanitizeSelector(j.hash)).html(l);h._cleanup();i.cache&&b.data(j,"cache.tabs", +true);h._trigger("load",null,h._ui(h.anchors[d],h.panels[d]));try{i.ajaxOptions.success(l,k)}catch(m){}},error:function(l,k){h._cleanup();h._trigger("load",null,h._ui(h.anchors[d],h.panels[d]));try{i.ajaxOptions.error(l,k,d,j)}catch(m){}}}));h.element.dequeue("tabs");return this}},abort:function(){this.element.queue([]);this.panels.stop(false,true);this.element.queue("tabs",this.element.queue("tabs").splice(-2,2));if(this.xhr){this.xhr.abort();delete this.xhr}this._cleanup();return this},url:function(d, +h){this.anchors.eq(d).removeData("cache.tabs").data("load.tabs",h);return this},length:function(){return this.anchors.length}});b.extend(b.ui.tabs,{version:"1.8.6"});b.extend(b.ui.tabs.prototype,{rotation:null,rotate:function(d,h){var i=this,j=this.options,n=i._rotate||(i._rotate=function(q){clearTimeout(i.rotation);i.rotation=setTimeout(function(){var l=j.selected;i.select(++l'; + } else { + display = sprintf("%02d:%02d:%02d", hours, minutes, seconds); + } + return this.html(display); + }; + + // Use true as second parameter to append "(You!)" + function formatBidder(name, withYou) { + if (name == USER_LOGIN) { + return "" + name + (withYou ? " (You!)" : "") + ""; + } else { + return name; + } + } + + function formatPrice(price) { + return '$' + Math.max(0, price).toFixed(2); + } + + function formatPercentage(json) { + return Math.max(0, Math.floor(100 * (1 - (json.p + json.investment.a) / RETAIL_PRICE))) + '%'; + } + + $.fn.bidHistory = function (json) { + var s = ""; + $.each(json.bids, function (key, bid) { + s += '' + formatBidder(bid.u, false) + '' + formatPrice(bid.p) + '' + bid.t + ''; + }); + return this.html(s); + }; + + $.fn.bidFlash = function (json, cache) { + var text = ""; + var nbid = json.n - cache.n; + var remaining = json.e * 1000 - fixTime(); + if (nbid !== 0) { + text += nbid + ((nbid == 1) ? ' Bid:' : ' Bids:'); + text += '     Price +' + formatPrice(json.p - cache.p); + if (remaining <= TIMER_RESET * 1000) { + text += '    Clock @' + TIMER_RESET + 'secs'; + } + } + return this.flash(text, 2500); + }; + + // Auction details page + function startOne(id) { + ticker = setInterval(tick, REFRESH_INTERVAL); + + function update(json, textStatus, xhr) { + setOffset(xhr); + if (!json.investment) { + json.investment = {a: 0, b: 0, c: 0}; + } + if (!cache) { + cache = json; + } + var a = A[json.id]; + a.$timer.countdown(json); + if (json.bot != null) { // may be 0, which would be false + a.$bid_bot_bids_left.val(json.bot); + if (json.bot == 0 && cache.bot > 0) { + auctionDialog("Warning", "Your Bid Assistant is out of Bids."); + }; + } + if (json.account) { + $(".credits-count").text(json.account.c); // todo: cache these jQuery objects + $(".bonuses-count").text(json.account.b); + if ((json.account.b + json.account.c == 0) && (cache.account.b + cache.account.c > 0)) { + auctionDialog("Warning", "Your account is out of Bids. Please purchase more Bid Credits to continue bidding."); + }; + }; + a.$going_price.highlight(json.p, cache.p, formatPrice); + a.$bidder.highlight(json.u, cache.u, formatBidder, true); + if (json.investment) { + a.$bonuses_used.highlight(json.investment.b, cache.investment.b); + a.$credits_used.highlight(json.investment.c, cache.investment.c); + a.$bids_value.highlight(json.investment.a, cache.investment.a, formatPrice); + a.$buy_now_price.highlight(RETAIL_PRICE - json.investment.a, RETAIL_PRICE - cache.investment.a, formatPrice); + a.$total_price.highlight(json.investment.a + json.p, cache.investment.a + cache.p, formatPrice); + a.$percentage.highlight(formatPercentage(json), formatPercentage(cache)); + } + a.$bid_button.setButton(json, cache); + if (json.n != cache.n) { + a.$flash.bidFlash(json, cache); + } + a.$bid_history.bidHistory(json); + if (json.done) { // End auction + clearInterval(ticker); + $('.auction-controls').hide(); + $('.auction-ended .credits-used-count').text(json.w.c); + $('.auction-ended .credits-used .value').text(formatPrice(json.w.a)); + $('.auction-ended .total-paid .value').text(formatPrice(json.wp)); + $('.auction-ended .bonuses-used-count').text(json.w.b); + $('.auction-ended .percentage').text(Math.max(0, Math.floor(100 * (1 - json.wp / RETAIL_PRICE))) + '%'); + $('.auction-ended').show(); + if (USER_LOGIN == json.u) { + $('.winner-button').show(); + } else { + $('.loser-button').show(); + } + location.reload(true); + } + cache = json; + } + + function auction_string() { + for (var key in A) { + if (A.hasOwnProperty(key)) { + return key; + } + } + } + + function tick() { + now = getNow(); + if (now - last_poll >= POLL_INTERVAL) { + $.ajax({ + url: '/poller/' + auction_string(), + dataType: 'json', + data: {u: USER_ID, t: now}, + success: update, + timeout: TIMEOUT + }); + last_poll = now; + } else if (cache) { + A[cache.id].$timer.countdown(cache); + } + } + } + + // Watchlist, homepage, history page + function startMany() { + ticker = setInterval(tick, REFRESH_INTERVAL); + + function ids() { + var s = ""; + $.each(A, function (id, val) {s += id + '-';}); + return s; + } + + function update(json, textStatus, xhr) { + setOffset(xhr); + if (!cache) { + cache = json; + } + if (json.bot != null) { // may be 0, which would be false + a.$bid_bot_bids_left.val(json.bot); + if (json.bot == 0 && cache.bot > 0) { + auctionDialog("Warning", "Your Bid Assistant is out of Bids."); + }; + } + if (json.account) { + $(".credits-count").text(json.account.c); // todo: cache these jQuery objects + $(".bonuses-count").text(json.account.b); + if ((json.account.b + json.account.c == 0) && (cache.account.b + cache.account.c > 0)) { + auctionDialog("Warning", "Your account is out of Bids. Please purchase more Bid Credits to continue bidding."); + }; + }; + for (var i = 0; i < json.auctions.length; i++) { + var x = json.auctions[i]; + var y = cache.auctions[i]; + var a = A[x.id]; + if (!a) { + continue; + } + a.$timer.countdown(x); + a.$going_price.highlight(x.p, y.p, formatPrice); + a.$bidder.highlight(x.u, y.u, formatBidder, false); + a.$bid_button.setButton(x, y); + if (x.investment) { + a.$buy_now_price.text(formatPrice(a.retail_price - x.investment.a)); + } + if (x.done) { + unregister(x.id); + $(".bid-button", a.$base).hide(); + $('.bidder-winner-label', a.$base).text("Winner:"); + if (USER_LOGIN === x.u) { + $('.winner-button', a.$base).show(); + $('.timer-container .winner-text', a.$base).show(); + $('.timer-container .ended-text', a.$base).hide(); + } else { + $('.loser-button', a.$base).show(); + $('.timer-container .winner-text', a.$base).hide(); + $('.timer-container .ended-text', a.$base).show(); + } + $('.timer-container .auction-timer', a.$base).hide(); + $(a.$base).addClass('ended-trigger'); + } + } + cache = json; + } + + function tick() { + now = getNow(); + if (now - last_poll >= POLL_INTERVAL) { + $.ajax({ + url: '/poller', + dataType: 'json', + data: {ids: ids(), t: now, u: USER_ID}, + success: update, + timeout: TIMEOUT + }); + last_poll = now; + } else if (cache) { + // Just update time + for (var i = 0; i < cache.auctions.length; i++) { + var info = cache.auctions[i]; + var a = A[info.id]; + if (!a) {continue;} + a.$timer.countdown(info); + } + } + } + } + +} \ No newline at end of file diff --git a/public/javascripts/protovis.js b/public/javascripts/protovis.js new file mode 100644 index 0000000..95bb3be --- /dev/null +++ b/public/javascripts/protovis.js @@ -0,0 +1,277 @@ +// fba9dc2 +var a;if(!Array.prototype.map)Array.prototype.map=function(b,c){for(var d=this.length,f=new Array(d),g=0;g>>0,f=0;f=d)throw new Error("reduce: no values, no initial value");}for(;f=0&&d=69&&m<100?1900:0)});return"([0-9]+)";case "%Y":q.push(function(m){g=m});return"([0-9]+)";case "%%":q.push(function(){}); +return"%"}return n});(f=f.match(o))&&f.forEach(function(n,m){q[m](n)});return new Date(g,h,i,j,l,k)};return c}; +pv.Format.time=function(b){function c(f){f=Number(f);switch(b){case "short":if(f>=31536E6)return(f/31536E6).toFixed(1)+" years";else if(f>=6048E5)return(f/6048E5).toFixed(1)+" weeks";else if(f>=864E5)return(f/864E5).toFixed(1)+" days";else if(f>=36E5)return(f/36E5).toFixed(1)+" hours";else if(f>=6E4)return(f/6E4).toFixed(1)+" minutes";return(f/1E3).toFixed(1)+" seconds";case "long":var g=[],h=f%36E5/6E4>>0;g.push(d("0",2,f%6E4/1E3>>0));if(f>=36E5){var i=f%864E5/36E5>>0;g.push(d("0",2,h));if(f>=864E5){g.push(d("0", +2,i));g.push(Math.floor(f/864E5).toFixed())}else g.push(i.toFixed())}else g.push(h.toFixed());return g.reverse().join(":")}}var d=pv.Format.pad;c.format=c;c.parse=function(f){switch(b){case "short":for(var g=/([0-9,.]+)\s*([a-z]+)/g,h,i=0;h=g.exec(f);){var j=parseFloat(h[0].replace(",","")),l=0;switch(h[2].toLowerCase()){case "year":case "years":l=31536E6;break;case "week":case "weeks":l=6048E5;break;case "day":case "days":l=864E5;break;case "hour":case "hours":l=36E5;break;case "minute":case "minutes":l= +6E4;break;case "second":case "seconds":l=1E3;break}i+=j*l}return i;case "long":h=f.replace(",","").split(":").reverse();i=0;if(h.length)i+=parseFloat(h[0])*1E3;if(h.length>1)i+=parseFloat(h[1])*6E4;if(h.length>2)i+=parseFloat(h[2])*36E5;if(h.length>3)i+=parseFloat(h[3])*864E5;return i}};return c}; +pv.Format.number=function(){function b(n){if(Infinity>h)n=Math.round(n*i)/i;var m=String(Math.abs(n)).split("."),r=m[0];n=n<0?"-":"";if(r.length>d)r=r.substring(r.length-d);if(k&&r.length3)r=r.replace(/\B(?=(?:\d{3})+(?!\d))/g,o);if(!k&&r.lengthd)m=m.substring(m.length-d);n=n[1]?Number("0."+n[1]):0;if(Infinity>h)n=Math.round(n*i)/i;return Math.round(m)+n};b.integerDigits=function(n,m){if(arguments.length){c=Number(n);d=arguments.length>1?Number(m):c;f=c+Math.floor(c/3)*o.length;return this}return[c,d]};b.fractionDigits=function(n,m){if(arguments.length){g= +Number(n);h=arguments.length>1?Number(m):g;i=Math.pow(10,h);return this}return[g,h]};b.integerPad=function(n){if(arguments.length){j=String(n);k=/\d/.test(j);return this}return j};b.fractionPad=function(n){if(arguments.length){l=String(n);return this}return l};b.decimal=function(n){if(arguments.length){q=String(n);return this}return q};b.group=function(n){if(arguments.length){o=n?String(n):"";f=c+Math.floor(c/3)*o.length;return this}return o};return b}; +pv.map=function(b,c){var d={};return c?b.map(function(f,g){d.index=g;return c.call(d,f)}):b.slice()};pv.repeat=function(b,c){if(arguments.length==1)c=2;return pv.blend(pv.range(c).map(function(){return b}))};pv.cross=function(b,c){for(var d=[],f=0,g=b.length,h=c.length;fc){b.length=d;for(var f=c;fc?1:0}; +pv.reverseOrder=function(b,c){return cb?1:0};pv.search=function(b,c,d){if(!d)d=pv.identity;for(var f=0,g=b.length-1;f<=g;){var h=f+g>>1,i=d(b[h]);if(ic)g=h-1;else return h}return-f-1};pv.search.index=function(b,c,d){b=pv.search(b,c,d);return b<0?-b-1:b}; +pv.range=function(b,c,d){if(arguments.length==1){c=b;b=0}if(d==undefined)d=1;if((c-b)/d==Infinity)throw new Error("range must be finite");var f=[],g=0,h;if(d<0)for(;(h=b+d*g++)>c;)f.push(h);else for(;(h=b+d*g++)f){f=i;d=h}}return d}; +pv.min=function(b,c){if(c==pv.index)return 0;return Math.min.apply(null,c?pv.map(b,c):b)};pv.min.index=function(b,c){if(!b.length)return-1;if(c==pv.index)return 0;if(!c)c=pv.identity;for(var d=0,f=Infinity,g={},h=0;h0?Math.pow(c,Math.floor(pv.log(b,c))):-Math.pow(c,-Math.floor(-pv.log(-b,c)))};pv.logCeil=function(b,c){return b>0?Math.pow(c,Math.ceil(pv.log(b,c))):-Math.pow(c,-Math.ceil(-pv.log(-b,c)))}; +(function(){var b=Math.PI/180,c=180/Math.PI;pv.radians=function(d){return b*d};pv.degrees=function(d){return c*d}})();pv.keys=function(b){var c=[];for(var d in b)c.push(d);return c};pv.entries=function(b){var c=[];for(var d in b)c.push({key:d,value:b[d]});return c};pv.values=function(b){var c=[];for(var d in b)c.push(b[d]);return c};pv.dict=function(b,c){for(var d={},f={},g=0;g=94608E6){n=31536E6;t="%Y";p=function(w){w.setFullYear(w.getFullYear()+v)}}else if(u>=7776E6){n=2592E6;t="%m/%Y";p=function(w){w.setMonth(w.getMonth()+v)}}else if(u>=18144E5){n=6048E5;t="%m/%d";p=function(w){w.setDate(w.getDate()+7*v)}}else if(u>=2592E5){n=864E5;t="%m/%d";p=function(w){w.setDate(w.getDate()+v)}}else if(u>=108E5){n=36E5;t="%I:%M %p";p=function(w){w.setHours(w.getHours()+ +v)}}else if(u>=18E4){n=6E4;t="%I:%M %p";p=function(w){w.setMinutes(w.getMinutes()+v)}}else if(u>=3E3){n=1E3;t="%I:%M:%S";p=function(w){w.setSeconds(w.getSeconds()+v)}}else{n=1;t="%S.%Qs";p=function(w){w.setTime(w.getTime()+v)}}q=pv.Format.date(t);s=new Date(s);t=[];x(s,n);u=u/n;if(u>10)switch(n){case 36E5:v=u>20?6:3;s.setHours(Math.floor(s.getHours()/v)*v);break;case 2592E6:v=3;s.setMonth(Math.floor(s.getMonth()/v)*v);break;case 6E4:v=u>30?15:u>15?10:5;s.setMinutes(Math.floor(s.getMinutes()/v)*v); +break;case 1E3:v=u>90?15:u>60?10:5;s.setSeconds(Math.floor(s.getSeconds()/v)*v);break;case 1:v=u>1E3?250:u>200?100:u>100?50:u>50?25:5;s.setMilliseconds(Math.floor(s.getMilliseconds()/v)*v);break;default:v=pv.logCeil(u/15,10);if(u/v<2)v/=5;else if(u/v<5)v/=2;s.setFullYear(Math.floor(s.getFullYear()/v)*v);break}for(;;){p(s);if(s>m)break;t.push(new Date(s))}return r?t.reverse():t}arguments.length||(o=10);v=pv.logFloor(u/o,10);n=o/(u/v);if(n<=0.15)v*=10;else if(n<=0.35)v*=5;else if(n<=0.75)v*=2;n=Math.ceil(s/ +v)*v;m=Math.floor(m/v)*v;q=pv.Format.number().fractionDigits(Math.max(0,-Math.floor(pv.log(v,10)+0.01)));m=pv.range(n,m+v,v);return r?m.reverse():m};c.tickFormat=function(o){return q(o)};c.nice=function(){if(d.length!=2)return this;var o=d[0],n=d[d.length-1],m=n0;i--)k.push(-g(-j)*i);else{for(;jh[1];l--);return k.slice(j,l)};b.tickFormat=function(h){return h.toPrecision(1)}; +b.nice=function(){var h=b.domain();return b.domain(pv.logFloor(h[0],c),pv.logCeil(h[1],c))};b.base=function(h){if(arguments.length){c=Number(h);d=Math.log(c);b.transform(f,g);return this}return c};b.domain.apply(b,arguments);return b.base(10)};pv.Scale.root=function(){var b=pv.Scale.quantitative();b.power=function(c){if(arguments.length){var d=Number(c),f=1/d;b.transform(function(g){return Math.pow(g,f)},function(g){return Math.pow(g,d)});return this}return d};b.domain.apply(b,arguments);return b.power(2)}; +pv.Scale.ordinal=function(){function b(g){g in d||(d[g]=c.push(g)-1);return f[d[g]%f.length]}var c=[],d={},f=[];b.domain=function(g,h){if(arguments.length){g=g instanceof Array?arguments.length>1?pv.map(g,h):g:Array.prototype.slice.call(arguments);c=[];for(var i={},j=0;j1?pv.map(g,h):g:Array.prototype.slice.call(arguments); +if(typeof f[0]=="string")f=f.map(pv.color);return this}return f};b.split=function(g,h){var i=(h-g)/this.domain().length;f=pv.range(g+i/2,h,i);return this};b.splitFlush=function(g,h){var i=this.domain().length,j=(h-g)/(i-1);f=i==1?[(g+h)/2]:pv.range(g,h+j/2,j);return this};b.splitBanded=function(g,h,i){if(arguments.length<3)i=1;if(i<0){var j=this.domain().length;j=(h-g- -i*j)/(j+1);f=pv.range(g+j,h,j-i);f.band=-i}else{j=(h-g)/(this.domain().length+(1-i));f=pv.range(g+j*(1-i),h,j);f.band=j*i}return this}; +b.by=function(g){function h(){return b(g.apply(this,arguments))}for(var i in b)h[i]=b[i];return h};b.domain.apply(b,arguments);return b}; +pv.Scale.quantile=function(){function b(i){return h(Math.max(0,Math.min(d,pv.search.index(f,i)-1))/d)}var c=-1,d=-1,f=[],g=[],h=pv.Scale.linear();b.quantiles=function(i){if(arguments.length){c=Number(i);if(c<0){f=[g[0]].concat(g);d=g.length-1}else{f=[];f[0]=g[0];for(var j=1;j<=c;j++)f[j]=g[~~(j*(g.length-1)/c)];d=c-1}return this}return f};b.domain=function(i,j){if(arguments.length){g=i instanceof Array?pv.map(i,j):Array.prototype.slice.call(arguments);g.sort(pv.naturalOrder);b.quantiles(c);return this}return g}; +b.range=function(){if(arguments.length){h.range.apply(h,arguments);return this}return h.range()};b.by=function(i){function j(){return b(i.apply(this,arguments))}for(var l in b)j[l]=b[l];return j};b.domain.apply(b,arguments);return b}; +pv.histogram=function(b,c){var d=true;return{bins:function(f){var g=pv.map(b,c),h=[];arguments.length||(f=pv.Scale.linear(g).ticks());for(var i=0;i360)j-=360;else if(j<0)j+=360;if(j<60)return i+(h-i)*j/60;if(j<180)return h;if(j<240)return i+(h-i)*(240-j)/60;return i}function c(j){return Math.round(b(j)*255)}var d=this.h,f=this.s,g=this.l;d%=360;if(d<0)d+=360;f=Math.max(0,Math.min(f,1));g=Math.max(0,Math.min(g,1));var h=g<=0.5?g*(1+f):g+f-g*f,i=2*g-h;return pv.rgb(c(d+120),c(d),c(d-120),this.a)}; +pv.Color.names={aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400", +darkgrey:"#a9a9a9",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc", +ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",green:"#008000",greenyellow:"#adff2f",grey:"#808080",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightgrey:"#d3d3d3",lightpink:"#ffb6c1",lightsalmon:"#ffa07a", +lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1", +moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57", +seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32",transparent:pv.Color.transparent=pv.rgb(0,0,0,0)};(function(){var b=pv.Color.names;for(var c in b)b[c]=pv.color(b[c])})(); +pv.colors=function(){var b=pv.Scale.ordinal();b.range.apply(b,arguments);return b};pv.Colors={};pv.Colors.category10=function(){var b=pv.colors("#1f77b4","#ff7f0e","#2ca02c","#d62728","#9467bd","#8c564b","#e377c2","#7f7f7f","#bcbd22","#17becf");b.domain.apply(b,arguments);return b}; +pv.Colors.category20=function(){var b=pv.colors("#1f77b4","#aec7e8","#ff7f0e","#ffbb78","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5","#8c564b","#c49c94","#e377c2","#f7b6d2","#7f7f7f","#c7c7c7","#bcbd22","#dbdb8d","#17becf","#9edae5");b.domain.apply(b,arguments);return b}; +pv.Colors.category19=function(){var b=pv.colors("#9c9ede","#7375b5","#4a5584","#cedb9c","#b5cf6b","#8ca252","#637939","#e7cb94","#e7ba52","#bd9e39","#8c6d31","#e7969c","#d6616b","#ad494a","#843c39","#de9ed6","#ce6dbd","#a55194","#7b4173");b.domain.apply(b,arguments);return b};pv.ramp=function(){var b=pv.Scale.linear();b.range.apply(b,arguments);return b}; +pv.Scene=pv.SvgScene={svg:"http://www.w3.org/2000/svg",xmlns:"http://www.w3.org/2000/xmlns",xlink:"http://www.w3.org/1999/xlink",xhtml:"http://www.w3.org/1999/xhtml",scale:1,events:["DOMMouseScroll","mousewheel","mousedown","mouseup","mouseover","mouseout","mousemove","click","dblclick"],implicit:{svg:{"shape-rendering":"auto","pointer-events":"painted",x:0,y:0,dy:0,"text-anchor":"start",transform:"translate(0,0)",fill:"none","fill-opacity":1,stroke:"none","stroke-opacity":1,"stroke-width":1.5,"stroke-linejoin":"miter"}, +css:{font:"10px sans-serif"}}};pv.SvgScene.updateAll=function(b){if(b.length&&b[0].reverse&&b.type!="line"&&b.type!="area"){for(var c=pv.extend(b),d=0,f=b.length-1;f>=0;d++,f--)c[d]=b[f];b=c}this.removeSiblings(this[b.type](b))};pv.SvgScene.create=function(b){return document.createElementNS(this.svg,b)}; +pv.SvgScene.expect=function(b,c,d,f){if(b){if(b.tagName=="a")b=b.firstChild;if(b.tagName!=c){c=this.create(c);b.parentNode.replaceChild(c,b);b=c}}else b=this.create(c);for(var g in d){c=d[g];if(c==this.implicit.svg[g])c=null;c==null?b.removeAttribute(g):b.setAttribute(g,c)}for(g in f){c=f[g];if(c==this.implicit.css[g])c=null;if(c==null)b.style.removeProperty(g);else b.style[g]=c}return b}; +pv.SvgScene.append=function(b,c,d){b.$scene={scenes:c,index:d};b=this.title(b,c[d]);b.parentNode||c.$g.appendChild(b);return b.nextSibling};pv.SvgScene.title=function(b,c){var d=b.parentNode;if(d&&d.tagName!="a")d=null;if(c.title){if(!d){d=this.create("a");b.parentNode&&b.parentNode.replaceChild(d,b);d.appendChild(b)}d.setAttributeNS(this.xlink,"title",c.title);return d}d&&d.parentNode.replaceChild(b,d);return b}; +pv.SvgScene.dispatch=pv.listener(function(b){var c=b.target.$scene;if(c){var d=b.type;switch(d){case "DOMMouseScroll":d="mousewheel";b.wheel=-480*b.detail;break;case "mousewheel":b.wheel=(window.opera?12:1)*b.wheelDelta;break}pv.Mark.dispatch(d,c.scenes,c.index)&&b.preventDefault()}});pv.SvgScene.removeSiblings=function(b){for(;b;){var c=b.nextSibling;b.parentNode.removeChild(b);b=c}};pv.SvgScene.undefined=function(){}; +pv.SvgScene.pathBasis=function(){function b(f,g,h,i,j){return{x:f[0]*g.left+f[1]*h.left+f[2]*i.left+f[3]*j.left,y:f[0]*g.top+f[1]*h.top+f[2]*i.top+f[3]*j.top}}var c=[[1/6,2/3,1/6,0],[0,2/3,1/3,0],[0,1/3,2/3,0],[0,1/6,2/3,1/6]],d=function(f,g,h,i){var j=b(c[1],f,g,h,i),l=b(c[2],f,g,h,i);f=b(c[3],f,g,h,i);return"C"+j.x+","+j.y+","+l.x+","+l.y+","+f.x+","+f.y};d.segment=function(f,g,h,i){var j=b(c[0],f,g,h,i),l=b(c[1],f,g,h,i),k=b(c[2],f,g,h,i);f=b(c[3],f,g,h,i);return"M"+j.x+","+j.y+"C"+l.x+","+l.y+ +","+k.x+","+k.y+","+f.x+","+f.y};return d}();pv.SvgScene.curveBasis=function(b){if(b.length<=2)return"";var c="",d=b[0],f=d,g=d,h=b[1];c+=this.pathBasis(d,f,g,h);for(var i=2;i1){j=c[1];h=b[l];l++;f+="C"+(g.left+i.x)+","+(g.top+i.y)+","+(h.left-j.x)+","+(h.top-j.y)+","+h.left+","+h.top;for(g=2;g9){l=3/Math.sqrt(l);f[h]= +l*i*d[h];f[h+1]=l*j*d[h]}}for(h=0;h2&&(g.interpolate=="basis"||g.interpolate=="cardinal"||g.interpolate=="monotone")?d:c)(k,q-1));k=q-1}}if(!j.length)return f;f=this.expect(f,"path",{"shape-rendering":g.antialias?null:"crispEdges","pointer-events":g.events,cursor:g.cursor,d:"M"+j.join("ZM")+"Z",fill:h.color,"fill-opacity":h.opacity|| +null,stroke:i.color,"stroke-opacity":i.opacity||null,"stroke-width":i.opacity?g.lineWidth/this.scale:null});return this.append(f,b,0)}; +pv.SvgScene.areaSegment=function(b){var c=b.$g.firstChild,d=b[0],f,g;if(d.interpolate=="basis"||d.interpolate=="cardinal"||d.interpolate=="monotone"){f=[];g=[];for(var h=0,i=b.length;h2&&(d.interpolate=="basis"||d.interpolate=="cardinal"||d.interpolate=="monotone"))switch(d.interpolate){case "basis":h+=this.curveBasis(b);break;case "cardinal":h+=this.curveCardinal(b,d.tension);break;case "monotone":h+=this.curveMonotone(b); +break}else for(var i=1;i1)break;return"A"+f+","+f+" 0 0,"+d+" "+c.left+","+c.top;case "step-before":return"V"+c.top+"H"+c.left;case "step-after":return"H"+c.left+"V"+c.top}return"L"+c.left+","+c.top};pv.SvgScene.lineIntersect=function(b,c,d,f){return b.plus(c.times(d.minus(b).dot(f.perp())/c.dot(f.perp())))}; +pv.SvgScene.pathJoin=function(b,c,d,f){var g=pv.vector(c.left,c.top);d=pv.vector(d.left,d.top);var h=d.minus(g),i=h.perp().norm(),j=i.times(c.lineWidth/(2*this.scale));c=g.plus(j);var l=d.plus(j),k=d.minus(j);j=g.minus(j);if(b&&b.visible){b=g.minus(b.left,b.top).perp().norm().plus(i);j=this.lineIntersect(g,b,j,h);c=this.lineIntersect(g,b,c,h)}if(f&&f.visible){f=pv.vector(f.left,f.top).minus(d).perp().norm().plus(i);k=this.lineIntersect(d,f,k,h);l=this.lineIntersect(d,f,l,h)}return"M"+c.x+","+c.y+ +"L"+l.x+","+l.y+" "+k.x+","+k.y+" "+j.x+","+j.y}; +pv.SvgScene.panel=function(b){for(var c=b.$g,d=c&&c.firstChild,f=0;f=2*Math.PI)i=i?"M0,"+j+"A"+j+","+j+" 0 1,1 0,"+-j+"A"+j+","+j+" 0 1,1 0,"+j+"M0,"+i+"A"+i+","+i+" 0 1,1 0,"+-i+"A"+i+","+i+" 0 1,1 0,"+i+"Z":"M0,"+j+"A"+j+","+j+" 0 1,1 0,"+-j+"A"+j+","+j+" 0 1,1 0,"+j+"Z";else{var k=Math.min(f.startAngle,f.endAngle),q=Math.max(f.startAngle,f.endAngle), +o=Math.cos(k),n=Math.cos(q);k=Math.sin(k);q=Math.sin(q);i=i?"M"+j*o+","+j*k+"A"+j+","+j+" 0 "+(l1?c:null)}; +a.anchor=function(b){function c(g){for(var h=d,i=[];!(f=h.scene);){g=g.parent;i.push({index:g.index,childIndex:h.childIndex});h=h.parent}for(;i.length;){g=i.pop();f=f[g.index].children[g.childIndex]}if(d.hasOwnProperty("index")){i=pv.extend(f[d.index]);i.right=i.top=i.left=i.bottom=0;return[i]}return f}var d=this,f;b||(b="center");return(new pv.Anchor(this)).name(b).def("$mark.anchor",function(){f=this.scene.target=c(this)}).data(function(){return f.map(function(g){return g.data})}).visible(function(){return f[this.index].visible}).left(function(){var g= +f[this.index],h=g.width||0;switch(this.name()){case "bottom":case "top":case "center":return g.left+h/2;case "left":return null}return g.left+h}).top(function(){var g=f[this.index],h=g.height||0;switch(this.name()){case "left":case "right":case "center":return g.top+h/2;case "top":return null}return g.top+h}).right(function(){var g=f[this.index];return this.name()=="left"?g.right+(g.width||0):null}).bottom(function(){var g=f[this.index];return this.name()=="top"?g.bottom+(g.height||0):null}).textAlign(function(){switch(this.name()){case "bottom":case "top":case "center":return"center"; +case "right":return"right"}return"left"}).textBaseline(function(){switch(this.name()){case "right":case "left":case "center":return"middle";case "top":return"top"}return"bottom"})};a.anchorTarget=function(){return this.proto.anchorTarget()};a.margin=function(b){return this.left(b).right(b).top(b).bottom(b)};a.instance=function(b){var c=this.scene||this.parent.instance(-1).children[this.childIndex],d=!arguments.length||this.hasOwnProperty("index")?this.index:b;return c[d<0?c.length-1:d]};a.first=function(){return this.scene[0]}; +a.last=function(){return this.scene[this.scene.length-1]};a.sibling=function(){return this.index==0?null:this.scene[this.index-1]};a.cousin=function(){var b=this.parent;return(b=b&&b.sibling())&&b.children?b.children[this.childIndex][this.index]:null}; +a.render=function(){function b(i,j,l){i.scale=l;if(j=0;k--){var q=l[k];if(!(q.name in c)){c[q.name]=q;switch(q.name){case "data":f=q;break;case "visible":g=q;break;default:d[q.type].push(q);break}}}while(j=j.proto)}var c={},d=[[],[],[],[]],f,g;b(this);b(this.defaults);d[1].reverse();d[3].reverse();var h=this;do for(var i in h.properties)i in c||d[2].push(c[i]={name:i,type:2,value:null});while(h=h.proto);h=d[0].concat(d[1]);for(i=0;ih.id)d[g.name]={id:0,value:g.type&1?g.value.apply(this,c):g.value}}}d=this.binds.data;d=d.type&1?d.value.apply(this,c):d.value;c.unshift(null); +b.length=d.length;for(f=0;f0;k--){n=m[k];n.scale=q;q*=n.scene[n.index].transform.k}if(o.children){k=0;for(m=o.children.length;k=3*Math.PI/2};pv.Wedge.prototype.buildImplied=function(b){if(b.angle==null)b.angle=b.endAngle-b.startAngle;else if(b.endAngle==null)b.endAngle=b.startAngle+b.angle;pv.Mark.prototype.buildImplied.call(this,b)};pv.simulation=function(b){return new pv.Simulation(b)};pv.Simulation=function(b){for(var c=0;c=s,t=q.y>=u;k.leaf=false;switch((t<<1)+x){case 0:k=k.c1||(k.c1=new pv.Quadtree.Node);break;case 1:k=k.c2||(k.c2=new pv.Quadtree.Node);break;case 2:k=k.c3||(k.c3=new pv.Quadtree.Node);break;case 3:k=k.c4||(k.c4=new pv.Quadtree.Node); +break}if(x)o=s;else m=s;if(t)n=u;else r=u;c(k,q,o,n,m,r)}var f,g=Number.POSITIVE_INFINITY,h=g,i=Number.NEGATIVE_INFINITY,j=i;for(f=b;f;f=f.next){if(f.xi)i=f.x;if(f.y>j)j=f.y}f=i-g;var l=j-h;if(f>l)j=h+f;else i=g+l;this.xMin=g;this.yMin=h;this.xMax=i;this.yMax=j;this.root=new pv.Quadtree.Node;for(f=b;f;f=f.next)c(this.root,f,g,h,i,j)};pv.Quadtree.Node=function(){this.leaf=true;this.p=this.c4=this.c3=this.c2=this.c1=null};pv.Force={}; +pv.Force.charge=function(b){function c(k){function q(m){c(m);k.cn+=m.cn;o+=m.cn*m.cx;n+=m.cn*m.cy}var o=0,n=0;k.cn=0;if(!k.leaf){k.c1&&q(k.c1);k.c2&&q(k.c2);k.c3&&q(k.c3);k.c4&&q(k.c4)}if(k.p){k.cn+=b;o+=b*k.p.x;n+=b*k.p.y}k.cx=o/k.cn;k.cy=n/k.cn}function d(k,q,o,n,m,r){var s=k.cx-q.x,u=k.cy-q.y,x=1/Math.sqrt(s*s+u*u);if(k.leaf&&k.p!=q||(m-o)*xg)x=g;k=k.cn*x*x*x;s=s*k;u=u*k;q.fx+=s;q.fy+=u}}else if(!k.leaf){var t=(o+m)*0.5,p=(n+r)*0.5;k.c1&&d(k.c1,q,o,n,t,p);k.c2&&d(k.c2,q,t,n, +m,p);k.c3&&d(k.c3,q,o,p,t,r);k.c4&&d(k.c4,q,t,p,m,r);if(!(xg)x=g;if(k.p&&k.p!=q){k=b*x*x*x;s=s*k;u=u*k;q.fx+=s;q.fy+=u}}}}var f=2,g=1/f,h=500,i=1/h,j=0.9,l={};arguments.length||(b=-40);l.constant=function(k){if(arguments.length){b=Number(k);return l}return b};l.domain=function(k,q){if(arguments.length){f=Number(k);g=1/f;h=Number(q);i=1/h;return l}return[f,h]};l.theta=function(k){if(arguments.length){j=Number(k);return l}return j};l.apply=function(k,q){c(q.root);for(k=k;k;k=k.next)d(q.root, +k,q.xMin,q.yMin,q.xMax,q.yMax)};return l};pv.Force.drag=function(b){var c={};arguments.length||(b=0.1);c.constant=function(d){if(arguments.length){b=d;return c}return b};c.apply=function(d){if(b)for(d=d;d;d=d.next){d.fx-=b*d.vx;d.fy-=b*d.vy}};return c}; +pv.Force.spring=function(b){var c=0.1,d=20,f,g,h={};arguments.length||(b=0.1);h.links=function(i){if(arguments.length){f=i;g=i.map(function(j){return 1/Math.sqrt(Math.max(j.sourceNode.linkDegree,j.targetNode.linkDegree))});return h}return f};h.constant=function(i){if(arguments.length){b=Number(i);return h}return b};h.damping=function(i){if(arguments.length){c=Number(i);return h}return c};h.length=function(i){if(arguments.length){d=Number(i);return h}return d};h.apply=function(){for(var i=0;ig,p=sh){k.c1&&t&&c(k.c1,q,o,n,s,u);k.c2&&p&&c(k.c2,q,s,n,m,u)}if(x){k.c3&&t&&c(k.c3,q,o,u,s,r);k.c4&&p&&c(k.c4,q,s,u,m,r)}}if(k.p&&k.p!=q){o=q.x-k.p.x;n=q.y-k.p.y;m=Math.sqrt(o*o+n*n);r=f+b(k.p);if(mm)m=n}for(var r=0;rc.max?c.max:g.x;if(d)for(g=f;g;g=g.next)g.y=g.yd.max?d.max:g.y};return b};pv.Layout=function(){pv.Panel.call(this)};pv.Layout.prototype=pv.extend(pv.Panel); +pv.Layout.prototype.property=function(b,c){if(!this.hasOwnProperty("properties"))this.properties=pv.extend(this.properties);this.properties[b]=true;this.propertyMethod(b,false,pv.Mark.cast[b]=c);return this}; +pv.Layout.Network=function(){pv.Layout.call(this);var b=this;this.$id=pv.id();(this.node=(new pv.Mark).data(function(){return b.nodes()}).strokeStyle("#1f77b4").fillStyle("#fff").left(function(c){return c.x}).top(function(c){return c.y})).parent=this;this.link=(new pv.Mark).extend(this.node).data(function(c){return[c.sourceNode,c.targetNode]}).fillStyle(null).lineWidth(function(c,d){return d.linkValue*1.5}).strokeStyle("rgba(0,0,0,.2)");this.link.add=function(c){return b.add(pv.Panel).data(function(){return b.links()}).add(c).extend(this)}; +(this.label=(new pv.Mark).extend(this.node).textMargin(7).textBaseline("middle").text(function(c){return c.nodeName||c.nodeValue}).textAngle(function(c){c=c.midAngle;return pv.Wedge.upright(c)?c:c+Math.PI}).textAlign(function(c){return pv.Wedge.upright(c.midAngle)?"left":"right"})).parent=this}; +pv.Layout.Network.prototype=pv.extend(pv.Layout).property("nodes",function(b){return b.map(function(c,d){if(typeof c!="object")c={nodeValue:c};c.index=d;c.linkDegree=0;return c})}).property("links",function(b){return b.map(function(c){if(isNaN(c.linkValue))c.linkValue=isNaN(c.value)?1:c.value;return c})});pv.Layout.Network.prototype.reset=function(){this.$id=pv.id();return this}; +pv.Layout.Network.prototype.buildProperties=function(b,c){if((b.$id||0)=this.$id)return true;b.$id=this.$id;b.links.forEach(function(c){var d=c.linkValue;(c.sourceNode||(c.sourceNode=b.nodes[c.source])).linkDegree+=d;(c.targetNode||(c.targetNode=b.nodes[c.target])).linkDegree+=d})}; +pv.Layout.Hierarchy=function(){pv.Layout.Network.call(this);this.link.strokeStyle("#ccc")};pv.Layout.Hierarchy.prototype=pv.extend(pv.Layout.Network);pv.Layout.Hierarchy.prototype.buildImplied=function(b){if(!b.links)b.links=pv.Layout.Hierarchy.links.call(this);pv.Layout.Network.prototype.buildImplied.call(this,b)};pv.Layout.Hierarchy.links=function(){return this.nodes().filter(function(b){return b.parentNode}).map(function(b){return{sourceNode:b,targetNode:b.parentNode,linkValue:1}})}; +pv.Layout.Hierarchy.NodeLink={buildImplied:function(b){function c(m){return m.parentNode?m.depth*(o-q)+q:0}function d(m){return m.parentNode?(m.breadth-0.25)*2*Math.PI:0}function f(m){switch(i){case "left":return m.depth*l;case "right":return l-m.depth*l;case "top":return m.breadth*l;case "bottom":return l-m.breadth*l;case "radial":return l/2+c(m)*Math.cos(m.midAngle)}}function g(m){switch(i){case "left":return m.breadth*k;case "right":return k-m.breadth*k;case "top":return m.depth*k;case "bottom":return k- +m.depth*k;case "radial":return k/2+c(m)*Math.sin(m.midAngle)}}var h=b.nodes,i=b.orient,j=/^(top|bottom)$/.test(i),l=b.width,k=b.height;if(i=="radial"){var q=b.innerRadius,o=b.outerRadius;if(q==null)q=0;if(o==null)o=Math.min(l,k)/2}for(b=0;bb.dy?0:-Math.PI/2});(this.leaf=(new pv.Mark).extend(this.node).fillStyle(null).strokeStyle(null).visible(function(b){return!b.firstChild})).parent= +this;delete this.link};pv.Layout.Treemap.prototype=pv.extend(pv.Layout.Hierarchy).property("round",Boolean).property("paddingLeft",Number).property("paddingRight",Number).property("paddingTop",Number).property("paddingBottom",Number).property("mode",String).property("order",String);a=pv.Layout.Treemap.prototype;a.defaults=(new pv.Layout.Treemap).extend(pv.Layout.Hierarchy.prototype.defaults).mode("squarify").order("ascending");a.padding=function(b){return this.paddingLeft(b).paddingRight(b).paddingTop(b).paddingBottom(b)}; +a.$size=function(b){return Number(b.nodeValue)};a.size=function(b){this.$size=pv.functor(b);return this}; +a.buildImplied=function(b){function c(r,s,u,x,t,p,v){for(var w=0,y=0;wu)u=v;t+=v}t*=t;s*=s;return Math.max(s*u/t,t/(s*x))}function f(r,s){function u(A){var D=p==y,G=pv.sum(A,o),E=y?n(G/y):0;c(A,G,D,x,t,D?p:E,D?E:v);if(D){t+=E;v-=E}else{x+= +E;p-=E}y=Math.min(p,v);return D}var x=r.x+j,t=r.y+k,p=r.dx-j-l,v=r.dy-k-q;if(m!="squarify")c(r.childNodes,r.size,m=="slice"?true:m=="dice"?false:s&1,x,t,p,v);else{var w=[];s=Infinity;var y=Math.min(p,v),z=p*v/r.size;if(!(r.size<=0)){r.visitBefore(function(A){A.size*=z});for(r=r.childNodes.slice();r.length;){var C=r[r.length-1];if(C.size){w.push(C);z=d(w,y);if(z<=s){r.pop();s=z}else{w.pop();u(w);w.length=0;s=Infinity}}else r.pop()}if(u(w))for(s=0;s0){i(l(C,p,v),p,B);A+=B;D+=B}G+=C.mod;A+=y.mod;E+=w.mod;D+=z.mod;C=h(C);y=g(y)}if(C&&!h(z)){z.thread=C;z.mod+=G-D}if(y&&!g(w)){w.thread=y;w.mod+=A-E;v=p}}return v}function g(p){return p.firstChild||p.thread}function h(p){return p.lastChild||p.thread}function i(p,v,w){var y=v.number-p.number;v.change-=w/y;v.shift+=w;p.change+= +w/y;v.prelim+=w;v.mod+=w}function j(p){var v=0,w=0;for(p=p.lastChild;p;p=p.previousSibling){p.prelim+=v;p.mod+=v;w+=p.change;v+=p.shift+w}}function l(p,v,w){return p.ancestor.parentNode==v.parentNode?p.ancestor:w}function k(p,v){return(v?1:u+1)/(m=="radial"?p:1)}function q(p){return m=="radial"?p.breadth/r:0}function o(p){switch(m){case "left":return p.depth;case "right":return x-p.depth;case "top":case "bottom":return p.breadth+x/2;case "radial":return x/2+p.depth*Math.cos(q(p))}}function n(p){switch(m){case "left":case "right":return p.breadth+ +t/2;case "top":return p.depth;case "bottom":return t-p.depth;case "radial":return t/2+p.depth*Math.sin(q(p))}}if(!pv.Layout.Hierarchy.prototype.buildImplied.call(this,b)){var m=b.orient,r=b.depth,s=b.breadth,u=b.group,x=b.width,t=b.height;b=b.nodes[0];b.visitAfter(function(p,v){p.ancestor=p;p.prelim=0;p.mod=0;p.change=0;p.shift=0;p.number=p.previousSibling?p.previousSibling.number+1:0;p.depth=v});c(b);d(b,-b.prelim,0);b.visitAfter(function(p){p.breadth*=s;p.depth*=r;p.midAngle=q(p);p.x=o(p);p.y=n(p); +if(p.firstChild)p.midAngle+=Math.PI;delete p.breadth;delete p.depth;delete p.ancestor;delete p.prelim;delete p.mod;delete p.change;delete p.shift;delete p.number;delete p.thread})}};pv.Layout.Indent=function(){pv.Layout.Hierarchy.call(this);this.link.interpolate("step-after")};pv.Layout.Indent.prototype=pv.extend(pv.Layout.Hierarchy).property("depth",Number).property("breadth",Number);pv.Layout.Indent.prototype.defaults=(new pv.Layout.Indent).extend(pv.Layout.Hierarchy.prototype.defaults).depth(15).breadth(15); +pv.Layout.Indent.prototype.buildImplied=function(b){function c(i,j,l){i.x=g+l++*f;i.y=h+j++*d;i.midAngle=0;for(i=i.firstChild;i;i=i.nextSibling)j=c(i,j,l);return j}if(!pv.Layout.Hierarchy.prototype.buildImplied.call(this,b)){var d=b.breadth,f=b.depth,g=0,h=0;c(b.nodes[0],1,1)}};pv.Layout.Pack=function(){pv.Layout.Hierarchy.call(this);this.node.radius(function(b){return b.radius}).strokeStyle("rgb(31, 119, 180)").fillStyle("rgba(31, 119, 180, .25)");this.label.textAlign("center");delete this.link}; +pv.Layout.Pack.prototype=pv.extend(pv.Layout.Hierarchy).property("spacing",Number).property("order",String);pv.Layout.Pack.prototype.defaults=(new pv.Layout.Pack).extend(pv.Layout.Hierarchy.prototype.defaults).spacing(1).order("ascending");pv.Layout.Pack.prototype.$radius=function(){return 1};pv.Layout.Pack.prototype.size=function(b){this.$radius=typeof b=="function"?function(){return Math.sqrt(b.apply(this,arguments))}:(b=Math.sqrt(b),function(){return b});return this}; +pv.Layout.Pack.prototype.buildImplied=function(b){function c(o){var n=pv.Mark.stack;n.unshift(null);for(var m=0,r=o.length;m0.0010}var u=Infinity,x=-Infinity,t=Infinity,p=-Infinity,v,w,y,z,C;v=o[0];v.x=-v.radius;v.y=0;n(v);if(o.length>1){w=o[1];w.x=w.radius;w.y=0;n(w);if(o.length>2){y=o[2];g(v,w,y);n(y);m(v,y);v.p= +y;m(y,w);w=v.n;for(var A=3;A0){r(v,z);w=z;A--}else if(D<0){r(z,w);v=z;A--}}}}v=(u+x)/2;w=(t+p)/2;for(A=y=0;Ao.min){o.sim.step(); +q=true}q&&d.render()},42)}else for(l=0;lg)g=j;i.size=i.firstChild?pv.sum(i.childNodes,function(l){return l.size}):c.$size.apply(c,(f[0]=i,f))});f.shift();switch(b.order){case "ascending":d.sort(function(i,j){return i.size-j.size});break;case "descending":d.sort(function(i,j){return j.size-i.size});break}var h=1/g;d.minBreadth=0;d.breadth= +0.5;d.maxBreadth=1;d.visitBefore(function(i){for(var j=i.minBreadth,l=i.maxBreadth-j,k=i.firstChild;k;k=k.nextSibling){k.minBreadth=j;k.maxBreadth=j+=k.size/i.size*l;k.breadth=(j+k.minBreadth)/2}});d.visitAfter(function(i,j){i.minDepth=(j-1)*h;i.maxDepth=i.depth=j*h});pv.Layout.Hierarchy.NodeLink.buildImplied.call(this,b)}};pv.Layout.Partition.Fill=function(){pv.Layout.Partition.call(this);pv.Layout.Hierarchy.Fill.constructor.call(this)};pv.Layout.Partition.Fill.prototype=pv.extend(pv.Layout.Partition); +pv.Layout.Partition.Fill.prototype.buildImplied=function(b){pv.Layout.Partition.prototype.buildImplied.call(this,b)||pv.Layout.Hierarchy.Fill.buildImplied.call(this,b)};pv.Layout.Arc=function(){pv.Layout.Network.call(this);var b,c,d,f=this.buildImplied;this.buildImplied=function(g){f.call(this,g);c=g.directed;b=g.orient=="radial"?"linear":"polar";d=g.orient=="right"||g.orient=="top"};this.link.data(function(g){var h=g.sourceNode;g=g.targetNode;return d!=(c||h.breadth>1)*f:null}).bottom(function(l,k){return d=="mirror"?k&1?null:(k+1>>1)*-f:(k&1||-1)*(k+1>>1)*f}).fillStyle(function(l,k){return(k&1?h:i)((k>>1)+1)});this.band.add=function(l){return b.add(pv.Panel).extend(c).add(l).extend(this)}};pv.Layout.Horizon.prototype=pv.extend(pv.Layout).property("bands",Number).property("mode",String).property("backgroundStyle",pv.color).property("positiveStyle",pv.color).property("negativeStyle",pv.color); +pv.Layout.Horizon.prototype.defaults=(new pv.Layout.Horizon).extend(pv.Layout.prototype.defaults).bands(2).mode("offset").backgroundStyle("white").positiveStyle("#1f77b4").negativeStyle("#d62728"); +pv.Layout.Rollup=function(){pv.Layout.Network.call(this);var b=this,c,d,f=b.buildImplied;this.buildImplied=function(g){f.call(this,g);c=g.$rollup.nodes;d=g.$rollup.links};this.node.data(function(){return c}).size(function(g){return g.nodes.length*20});this.link.interpolate("polar").eccentricity(0.8);this.link.add=function(g){return b.add(pv.Panel).data(function(){return d}).add(g).extend(this)}};pv.Layout.Rollup.prototype=pv.extend(pv.Layout.Network).property("directed",Boolean); +pv.Layout.Rollup.prototype.x=function(b){this.$x=pv.functor(b);return this};pv.Layout.Rollup.prototype.y=function(b){this.$y=pv.functor(b);return this}; +pv.Layout.Rollup.prototype.buildImplied=function(b){function c(r){return i[r]+","+j[r]}if(!pv.Layout.Network.prototype.buildImplied.call(this,b)){var d=b.nodes,f=b.links,g=b.directed,h=d.length,i=[],j=[],l=0,k={},q={},o=pv.Mark.stack,n={parent:this};o.unshift(null);for(var m=0;ml.index?l.index+","+d.index:d.index+","+l.index;(o=q[h])||(o=q[h]={sourceNode:d,targetNode:l,linkValue:0,links:[]});o.links.push(f[m]);o.linkValue+=f[m].linkValue}b.$rollup={nodes:pv.values(k),links:pv.values(q)}}}; +pv.Layout.Matrix=function(){pv.Layout.Network.call(this);var b,c,d,f,g,h=this.buildImplied;this.buildImplied=function(i){h.call(this,i);b=i.nodes.length;c=i.width/b;d=i.height/b;f=i.$matrix.labels;g=i.$matrix.pairs};this.link.data(function(){return g}).left(function(){return c*(this.index%b)}).top(function(){return d*Math.floor(this.index/b)}).width(function(){return c}).height(function(){return d}).lineWidth(1.5).strokeStyle("#fff").fillStyle(function(i){return i.linkValue?"#555":"#eee"}).parent= +this;delete this.link.add;this.label.data(function(){return f}).left(function(){return this.index&1?c*((this.index>>1)+0.5):null}).top(function(){return this.index&1?null:d*((this.index>>1)+0.5)}).textMargin(4).textAlign(function(){return this.index&1?"left":"right"}).textAngle(function(){return this.index&1?-Math.PI/2:0});delete this.node};pv.Layout.Matrix.prototype=pv.extend(pv.Layout.Network).property("directed",Boolean);pv.Layout.Matrix.prototype.sort=function(b){this.$sort=b;return this}; +pv.Layout.Matrix.prototype.buildImplied=function(b){if(!pv.Layout.Network.prototype.buildImplied.call(this,b)){var c=b.nodes,d=b.links,f=this.$sort,g=c.length,h=pv.range(g),i=[],j=[],l={};b.$matrix={labels:i,pairs:j};f&&h.sort(function(m,r){return f(c[m],c[r])});for(var k=0;kl)k=null;if(g){if(k&&g.scene==k.scene&&g.index==k.index)return;pv.Mark.dispatch("unpoint",g.scene,g.index)}if(g=k){pv.Mark.dispatch("point",k.scene,k.index);pv.listen(this.root.canvas(),"mouseout",f)}}function f(k){if(g&&!pv.ancestor(this,k.relatedTarget)){pv.Mark.dispatch("unpoint",g.scene,g.index);g=null}}var g,h=null,i=1,j=1,l=arguments.length?b*b:900;d.collapse=function(k){if(arguments.length){h=String(k);switch(h){case "y":i= +1;j=0;break;case "x":i=0;j=1;break;default:j=i=1;break}return d}return h};return d}; +pv.Behavior.select=function(){function b(j){g=this.index;f=this.scene;i=this.mouse();h=j;h.x=i.x;h.y=i.y;h.dx=h.dy=0;pv.Mark.dispatch("selectstart",f,g)}function c(){if(f){f.mark.context(f,g,function(){var j=this.mouse();h.x=Math.max(0,Math.min(i.x,j.x));h.y=Math.max(0,Math.min(i.y,j.y));h.dx=Math.min(this.width(),Math.max(j.x,i.x))-h.x;h.dy=Math.min(this.height(),Math.max(j.y,i.y))-h.y;this.render()});pv.Mark.dispatch("select",f,g)}}function d(){if(f){pv.Mark.dispatch("selectend",f,g);f=null}}var f, +g,h,i;pv.listen(window,"mousemove",c);pv.listen(window,"mouseup",d);return b}; +pv.Behavior.resize=function(b){function c(l){h=this.index;g=this.scene;j=this.mouse();i=l;switch(b){case "left":j.x=i.x+i.dx;break;case "right":j.x=i.x;break;case "top":j.y=i.y+i.dy;break;case "bottom":j.y=i.y;break}pv.Mark.dispatch("resizestart",g,h)}function d(){if(g){g.mark.context(g,h,function(){var l=this.mouse();i.x=Math.max(0,Math.min(j.x,l.x));i.y=Math.max(0,Math.min(j.y,l.y));i.dx=Math.min(this.parent.width(),Math.max(l.x,j.x))-i.x;i.dy=Math.min(this.parent.height(),Math.max(l.y,j.y))-i.y; +this.render()});pv.Mark.dispatch("resize",g,h)}}function f(){if(g){pv.Mark.dispatch("resizeend",g,h);g=null}}var g,h,i,j;pv.listen(window,"mousemove",d);pv.listen(window,"mouseup",f);return c}; +pv.Behavior.pan=function(){function b(){g=this.index;f=this.scene;i=pv.vector(pv.event.pageX,pv.event.pageY);h=this.transform();j=1/(h.k*this.scale);if(l)l={x:(1-h.k)*this.width(),y:(1-h.k)*this.height()}}function c(){if(f){f.mark.context(f,g,function(){var k=h.translate((pv.event.pageX-i.x)*j,(pv.event.pageY-i.y)*j);if(l){k.x=Math.max(l.x,Math.min(0,k.x));k.y=Math.max(l.y,Math.min(0,k.y))}this.transform(k).render()});pv.Mark.dispatch("pan",f,g)}}function d(){f=null}var f,g,h,i,j,l;b.bound=function(k){if(arguments.length){l= +Boolean(k);return this}return Boolean(l)};pv.listen(window,"mousemove",c);pv.listen(window,"mouseup",d);return b}; +pv.Behavior.zoom=function(b){function c(){var f=this.mouse(),g=pv.event.wheel*b;f=this.transform().translate(f.x,f.y).scale(g<0?1E3/(1E3-g):(1E3+g)/1E3).translate(-f.x,-f.y);if(d){f.k=Math.max(1,f.k);f.x=Math.max((1-f.k)*this.width(),Math.min(0,f.x));f.y=Math.max((1-f.k)*this.height(),Math.min(0,f.y))}this.transform(f).render();pv.Mark.dispatch("zoom",this.scene,this.index)}var d;arguments.length||(b=1/48);c.bound=function(f){if(arguments.length){d=Boolean(f);return this}return Boolean(d)};return c}; +pv.Geo=function(){}; +pv.Geo.projections={mercator:{project:function(b){return{x:b.lng/180,y:b.lat>85?1:b.lat<-85?-1:Math.log(Math.tan(Math.PI/4+pv.radians(b.lat)/2))/Math.PI}},invert:function(b){return{lng:b.x*180,lat:pv.degrees(2*Math.atan(Math.exp(b.y*Math.PI))-Math.PI/2)}}},"gall-peters":{project:function(b){return{x:b.lng/180,y:Math.sin(pv.radians(b.lat))}},invert:function(b){return{lng:b.x*180,lat:pv.degrees(Math.asin(b.y))}}},sinusoidal:{project:function(b){return{x:pv.radians(b.lng)*Math.cos(pv.radians(b.lat))/Math.PI, +y:b.lat/90}},invert:function(b){return{lng:pv.degrees(b.x*Math.PI/Math.cos(b.y*Math.PI/2)),lat:b.y*90}}},aitoff:{project:function(b){var c=pv.radians(b.lng);b=pv.radians(b.lat);var d=Math.acos(Math.cos(b)*Math.cos(c/2));return{x:2*(d?Math.cos(b)*Math.sin(c/2)*d/Math.sin(d):0)/Math.PI,y:2*(d?Math.sin(b)*d/Math.sin(d):0)/Math.PI}},invert:function(b){var c=b.y*Math.PI/2;return{lng:pv.degrees(b.x*Math.PI/2/Math.cos(c)),lat:pv.degrees(c)}}},hammer:{project:function(b){var c=pv.radians(b.lng);b=pv.radians(b.lat); +var d=Math.sqrt(1+Math.cos(b)*Math.cos(c/2));return{x:2*Math.SQRT2*Math.cos(b)*Math.sin(c/2)/d/3,y:Math.SQRT2*Math.sin(b)/d/1.5}},invert:function(b){var c=b.x*3;b=b.y*1.5;var d=Math.sqrt(1-c*c/16-b*b/4);return{lng:pv.degrees(2*Math.atan2(d*c,2*(2*d*d-1))),lat:pv.degrees(Math.asin(d*b))}}},identity:{project:function(b){return{x:b.lng/180,y:b.lat/90}},invert:function(b){return{lng:b.x*180,lat:b.y*90}}}}; +pv.Geo.scale=function(b){function c(m){if(!o||m.lng!=o.lng||m.lat!=o.lat){o=m;m=d(m);n={x:l(m.x),y:k(m.y)}}return n}function d(m){return j.project({lng:m.lng-q.lng,lat:m.lat})}function f(m){m=j.invert(m);m.lng+=q.lng;return m}var g={x:0,y:0},h={x:1,y:1},i=[],j=pv.Geo.projections.identity,l=pv.Scale.linear(-1,1).range(0,1),k=pv.Scale.linear(-1,1).range(1,0),q={lng:0,lat:0},o,n;c.x=function(m){return c(m).x};c.y=function(m){return c(m).y};c.ticks={lng:function(m){var r;if(i.length>1){var s=pv.Scale.linear(); +if(m==undefined)m=10;r=s.domain(i,function(u){return u.lat}).ticks(m);m=s.domain(i,function(u){return u.lng}).ticks(m)}else{r=pv.range(-80,81,10);m=pv.range(-180,181,10)}return m.map(function(u){return r.map(function(x){return{lat:x,lng:u}})})},lat:function(m){return pv.transpose(c.ticks.lng(m))}};c.invert=function(m){return f({x:l.invert(m.x),y:k.invert(m.y)})};c.domain=function(m,r){if(arguments.length){i=m instanceof Array?arguments.length>1?pv.map(m,r):m:Array.prototype.slice.call(arguments); +if(i.length>1){var s=i.map(function(x){return x.lng}),u=i.map(function(x){return x.lat});q={lng:(pv.max(s)+pv.min(s))/2,lat:(pv.max(u)+pv.min(u))/2};s=i.map(d);l.domain(s,function(x){return x.x});k.domain(s,function(x){return x.y})}else{q={lng:0,lat:0};l.domain(-1,1);k.domain(-1,1)}o=null;return this}return i};c.range=function(m,r){if(arguments.length){if(typeof m=="object"){g={x:Number(m.x),y:Number(m.y)};h={x:Number(r.x),y:Number(r.y)}}else{g={x:0,y:0};h={x:Number(m),y:Number(r)}}l.range(g.x,h.x); +k.range(h.y,g.y);o=null;return this}return[g,h]};c.projection=function(m){if(arguments.length){j=typeof m=="string"?pv.Geo.projections[m]||pv.Geo.projections.identity:m;return this.domain(i)}return m};c.by=function(m){function r(){return c(m.apply(this,arguments))}for(var s in c)r[s]=c[s];return r};arguments.length&&c.projection(b);return c}; diff --git a/public/javascripts/rails.js b/public/javascripts/rails.js new file mode 100644 index 0000000..9178e96 --- /dev/null +++ b/public/javascripts/rails.js @@ -0,0 +1,315 @@ +/** + * Unobtrusive scripting adapter for jQuery + * + * Requires jQuery 1.4.4 or later. + * https://github.com/rails/jquery-ujs + + * Uploading file using rails.js + * ============================= + * + * By default, browsers do not allow files to be uploaded via AJAX. As a result, if there are any non-blank file fields + * in the remote form, this adapter aborts the AJAX submission and allows the form to submit through standard means. + * + * The `ajax:aborted:file` event allows you to bind your own handler to process the form submission however you wish. + * + * Ex: + * $('form').live('ajax:aborted:file', function(event, elements){ + * // Implement own remote file-transfer handler here for non-blank file inputs passed in `elements`. + * // Returning false in this handler tells rails.js to disallow standard form submission + * return false; + * }); + * + * The `ajax:aborted:file` event is fired when a file-type input is detected with a non-blank value. + * + * Third-party tools can use this hook to detect when an AJAX file upload is attempted, and then use + * techniques like the iframe method to upload the file instead. + * + * Required fields in rails.js + * =========================== + * + * If any blank required inputs (required="required") are detected in the remote form, the whole form submission + * is canceled. Note that this is unlike file inputs, which still allow standard (non-AJAX) form submission. + * + * The `ajax:aborted:required` event allows you to bind your own handler to inform the user of blank required inputs. + * + * !! Note that Opera does not fire the form's submit event if there are blank required inputs, so this event may never + * get fired in Opera. This event is what causes other browsers to exhibit the same submit-aborting behavior. + * + * Ex: + * $('form').live('ajax:aborted:required', function(event, elements){ + * // Returning false in this handler tells rails.js to submit the form anyway. + * // The blank required inputs are passed to this function in `elements`. + * return ! confirm("Would you like to submit the form with missing info?"); + * }); + */ + +(function($) { + // Shorthand to make it a little easier to call public rails functions from within rails.js + var rails; + + $.rails = rails = { + // Link elements bound by jquery-ujs + linkClickSelector: 'a[data-confirm], a[data-method], a[data-remote]', + + // Form elements bound by jquery-ujs + formSubmitSelector: 'form', + + // Form input elements bound by jquery-ujs + formInputClickSelector: 'form input[type=submit], form input[type=image], form button[type=submit], form button:not([type])', + + // Form input elements disabled during form submission + disableSelector: 'input[data-disable-with], button[data-disable-with], textarea[data-disable-with]', + + // Form input elements re-enabled after form submission + enableSelector: 'input[data-disable-with]:disabled, button[data-disable-with]:disabled, textarea[data-disable-with]:disabled', + + // Form required input elements + requiredInputSelector: 'input[name][required],textarea[name][required]', + + // Form file input elements + fileInputSelector: 'input:file', + + // Make sure that every Ajax request sends the CSRF token + CSRFProtection: function(xhr) { + var token = $('meta[name="csrf-token"]').attr('content'); + if (token) xhr.setRequestHeader('X-CSRF-Token', token); + }, + + // Triggers an event on an element and returns false if the event result is false + fire: function(obj, name, data) { + var event = $.Event(name); + obj.trigger(event, data); + return event.result !== false; + }, + + // Default confirm dialog, may be overridden with custom confirm dialog in $.rails.confirm + confirm: function(message) { + return confirm(message); + }, + + // Default ajax function, may be overridden with custom function in $.rails.ajax + ajax: function(options) { + return $.ajax(options); + }, + + // Submits "remote" forms and links with ajax + handleRemote: function(element) { + var method, url, data, + dataType = element.data('type') || ($.ajaxSettings && $.ajaxSettings.dataType); + + if (rails.fire(element, 'ajax:before')) { + + if (element.is('form')) { + method = element.attr('method'); + url = element.attr('action'); + data = element.serializeArray(); + // memoized value from clicked submit button + var button = element.data('ujs:submit-button'); + if (button) { + data.push(button); + element.data('ujs:submit-button', null); + } + } else { + method = element.data('method'); + url = element.attr('href'); + data = null; + } + + rails.ajax({ + url: url, type: method || 'GET', data: data, dataType: dataType, + // stopping the "ajax:beforeSend" event will cancel the ajax request + beforeSend: function(xhr, settings) { + if (settings.dataType === undefined) { + xhr.setRequestHeader('accept', '*/*;q=0.5, ' + settings.accepts.script); + } + return rails.fire(element, 'ajax:beforeSend', [xhr, settings]); + }, + success: function(data, status, xhr) { + element.trigger('ajax:success', [data, status, xhr]); + }, + complete: function(xhr, status) { + element.trigger('ajax:complete', [xhr, status]); + }, + error: function(xhr, status, error) { + element.trigger('ajax:error', [xhr, status, error]); + } + }); + } + }, + + // Handles "data-method" on links such as: + // Delete + handleMethod: function(link) { + var href = link.attr('href'), + method = link.data('method'), + csrf_token = $('meta[name=csrf-token]').attr('content'), + csrf_param = $('meta[name=csrf-param]').attr('content'), + form = $('
    '), + metadata_input = ''; + + if (csrf_param !== undefined && csrf_token !== undefined) { + metadata_input += ''; + } + + form.hide().append(metadata_input).appendTo('body'); + form.submit(); + }, + + /* Disables form elements: + - Caches element value in 'ujs:enable-with' data store + - Replaces element text with value of 'data-disable-with' attribute + - Adds disabled=disabled attribute + */ + disableFormElements: function(form) { + form.find(rails.disableSelector).each(function() { + var element = $(this), method = element.is('button') ? 'html' : 'val'; + element.data('ujs:enable-with', element[method]()); + element[method](element.data('disable-with')); + element.attr('disabled', 'disabled'); + }); + }, + + /* Re-enables disabled form elements: + - Replaces element text with cached value from 'ujs:enable-with' data store (created in `disableFormElements`) + - Removes disabled attribute + */ + enableFormElements: function(form) { + form.find(rails.enableSelector).each(function() { + var element = $(this), method = element.is('button') ? 'html' : 'val'; + if (element.data('ujs:enable-with')) element[method](element.data('ujs:enable-with')); + element.removeAttr('disabled'); + }); + }, + + /* For 'data-confirm' attribute: + - Fires `confirm` event + - Shows the confirmation dialog + - Fires the `confirm:complete` event + + Returns `true` if no function stops the chain and user chose yes; `false` otherwise. + Attaching a handler to the element's `confirm` event that returns a `falsy` value cancels the confirmation dialog. + Attaching a handler to the element's `confirm:complete` event that returns a `falsy` value makes this function + return false. The `confirm:complete` event is fired whether or not the user answered true or false to the dialog. + */ + allowAction: function(element) { + var message = element.data('confirm'), + answer = false, callback; + if (!message) { return true; } + + if (rails.fire(element, 'confirm')) { + answer = rails.confirm(message); + callback = rails.fire(element, 'confirm:complete', [answer]); + } + return answer && callback; + }, + + // Helper function which checks for blank inputs in a form that match the specified CSS selector + blankInputs: function(form, specifiedSelector, nonBlank) { + var inputs = $(), input, + selector = specifiedSelector || 'input,textarea'; + form.find(selector).each(function() { + input = $(this); + // Collect non-blank inputs if nonBlank option is true, otherwise, collect blank inputs + if (nonBlank ? input.val() : !input.val()) { + inputs = inputs.add(input); + } + }); + return inputs.length ? inputs : false; + }, + + // Helper function which checks for non-blank inputs in a form that match the specified CSS selector + nonBlankInputs: function(form, specifiedSelector) { + return rails.blankInputs(form, specifiedSelector, true); // true specifies nonBlank + }, + + // Helper function, needed to provide consistent behavior in IE + stopEverything: function(e) { + $(e.target).trigger('ujs:everythingStopped'); + e.stopImmediatePropagation(); + return false; + }, + + // find all the submit events directly bound to the form and + // manually invoke them. If anyone returns false then stop the loop + callFormSubmitBindings: function(form) { + var events = form.data('events'), continuePropagation = true; + if (events !== undefined && events['submit'] !== undefined) { + $.each(events['submit'], function(i, obj){ + if (typeof obj.handler === 'function') return continuePropagation = obj.handler(obj.data); + }); + } + return continuePropagation; + } + }; + + // ajaxPrefilter is a jQuery 1.5 feature + if ('ajaxPrefilter' in $) { + $.ajaxPrefilter(function(options, originalOptions, xhr){ rails.CSRFProtection(xhr); }); + } else { + $(document).ajaxSend(function(e, xhr){ rails.CSRFProtection(xhr); }); + } + + $(rails.linkClickSelector).live('click.rails', function(e) { + var link = $(this); + if (!rails.allowAction(link)) return rails.stopEverything(e); + + if (link.data('remote') !== undefined) { + rails.handleRemote(link); + return false; + } else if (link.data('method')) { + rails.handleMethod(link); + return false; + } + }); + + $(rails.formSubmitSelector).live('submit.rails', function(e) { + var form = $(this), + remote = form.data('remote') !== undefined, + blankRequiredInputs = rails.blankInputs(form, rails.requiredInputSelector), + nonBlankFileInputs = rails.nonBlankInputs(form, rails.fileInputSelector); + + if (!rails.allowAction(form)) return rails.stopEverything(e); + + // skip other logic when required values are missing or file upload is present + if (blankRequiredInputs && rails.fire(form, 'ajax:aborted:required', [blankRequiredInputs])) { + return rails.stopEverything(e); + } + + if (remote) { + if (nonBlankFileInputs) { + return rails.fire(form, 'ajax:aborted:file', [nonBlankFileInputs]); + } + + // If browser does not support submit bubbling, then this live-binding will be called before direct + // bindings. Therefore, we should directly call any direct bindings before remotely submitting form. + if (!$.support.submitBubbles && rails.callFormSubmitBindings(form) === false) return rails.stopEverything(e); + + rails.handleRemote(form); + return false; + } else { + // slight timeout so that the submit button gets properly serialized + setTimeout(function(){ rails.disableFormElements(form); }, 13); + } + }); + + $(rails.formInputClickSelector).live('click.rails', function(event) { + var button = $(this); + + if (!rails.allowAction(button)) return rails.stopEverything(event); + + // register the pressed submit button + var name = button.attr('name'), + data = name ? {name:name, value:button.val()} : null; + + button.closest('form').data('ujs:submit-button', data); + }); + + $(rails.formSubmitSelector).live('ajax:beforeSend.rails', function(event) { + if (this == event.target) rails.disableFormElements($(this)); + }); + + $(rails.formSubmitSelector).live('ajax:complete.rails', function(event) { + if (this == event.target) rails.enableFormElements($(this)); + }); + +})( jQuery ); diff --git a/public/javascripts/slideshow.js b/public/javascripts/slideshow.js new file mode 100644 index 0000000..aa3d901 --- /dev/null +++ b/public/javascripts/slideshow.js @@ -0,0 +1,44 @@ +jQuery.fn.slideshow = function() { + var settings = { + fadetime: 1200, + timeout: 8000 + }; + var current = 1, last = 0, timer = ''; + + var change = function () { + for (var i = 0; i < slides.length; i++) { + jQuery(slides[i]).css('display', 'none'); + } + jQuery(slides[last]).css('display', 'block').css('zIndex', '0'); + + jQuery(slides[current]).css('zIndex', '1').fadeIn(settings.fadetime); + + if ( ( current + 1 ) < slides.length ) { + current = current + 1; + last = current - 1; + } else { + current = 0; + last = slides.length - 1; + } + timer = setTimeout(change, settings.timeout); + }; + var slides = this.find('div').get(); + jQuery.each(slides, function(i){ + jQuery(slides[i]).css('zIndex', slides.length - i); + }); + + timer = setTimeout(change, settings.timeout); + + // pause on hover + $('#slideshow div.image-map').hover(function(){ + clearTimeout(timer); + },function(){ + timer = setTimeout(change, settings.timeout); + }); + return this; +}; + +$(document).ready(function() { + // INITIATE SLIDESHOW + $('#slideshow').slideshow(); +}); \ No newline at end of file diff --git a/public/javascripts/sprintf.js b/public/javascripts/sprintf.js new file mode 100644 index 0000000..0a6a867 --- /dev/null +++ b/public/javascripts/sprintf.js @@ -0,0 +1,128 @@ +/*! + * Javascript sprintf + * http://www.webtoolkit.info/ + */ + +sprintfWrapper = { + + init : function () { + + if (typeof arguments == "undefined") { return null; } + if (arguments.length < 1) { return null; } + if (typeof arguments[0] != "string") { return null; } + if (typeof RegExp == "undefined") { return null; } + + var string = arguments[0]; + var exp = new RegExp(/(%([%]|(\-)?(\+|\x20)?(0)?(\d+)?(\.(\d)?)?([bcdfosxX])))/g); + var matches = new Array(); + var strings = new Array(); + var convCount = 0; + var stringPosStart = 0; + var stringPosEnd = 0; + var matchPosEnd = 0; + var newString = ''; + var match = null; + + while (match = exp.exec(string)) { + if (match[9]) { convCount += 1; } + + stringPosStart = matchPosEnd; + stringPosEnd = exp.lastIndex - match[0].length; + strings[strings.length] = string.substring(stringPosStart, stringPosEnd); + + matchPosEnd = exp.lastIndex; + matches[matches.length] = { + match: match[0], + left: match[3] ? true : false, + sign: match[4] || '', + pad: match[5] || ' ', + min: match[6] || 0, + precision: match[8], + code: match[9] || '%', + negative: parseInt(arguments[convCount]) < 0 ? true : false, + argument: String(arguments[convCount]) + }; + } + strings[strings.length] = string.substring(matchPosEnd); + + if (matches.length == 0) { return string; } + if ((arguments.length - 1) < convCount) { return null; } + + var code = null; + var match = null; + var i = null; + + for (i=0; i'); + var tiptip_content = $('
    '); + var tiptip_arrow = $('
    '); + $("body").append(tiptip_holder.html(tiptip_content).prepend(tiptip_arrow.html('
    '))); + } else { + var tiptip_holder = $("#tiptip_holder"); + var tiptip_content = $("#tiptip_content"); + var tiptip_arrow = $("#tiptip_arrow"); + } + + return this.each(function(){ + var org_elem = $(this); + if(opts.content){ + var org_title = opts.content; + } else { + var org_title = org_elem.attr(opts.attribute); + } + if(org_title != ""){ + if(!opts.content){ + org_elem.removeAttr(opts.attribute); //remove original Attribute + } + var timeout = false; + + if(opts.activation == "hover"){ + org_elem.hover(function(){ + active_tiptip(); + }, function(){ + if(!opts.keepAlive){ + deactive_tiptip(); + } + }); + if(opts.keepAlive){ + tiptip_holder.hover(function(){}, function(){ + deactive_tiptip(); + }); + } + } else if(opts.activation == "focus"){ + org_elem.focus(function(){ + active_tiptip(); + }).blur(function(){ + deactive_tiptip(); + }); + } else if(opts.activation == "click"){ + org_elem.click(function(){ + active_tiptip(); + return false; + }).hover(function(){},function(){ + if(!opts.keepAlive){ + deactive_tiptip(); + } + }); + if(opts.keepAlive){ + tiptip_holder.hover(function(){}, function(){ + deactive_tiptip(); + }); + } + } + + function active_tiptip(){ + opts.enter.call(this); + tiptip_content.html(org_title); + tiptip_holder.hide().removeAttr("class").css("margin","0"); + tiptip_arrow.removeAttr("style"); + + var top = parseInt(org_elem.offset()['top']); + var left = parseInt(org_elem.offset()['left']); + var org_width = parseInt(org_elem.outerWidth()); + var org_height = parseInt(org_elem.outerHeight()); + var tip_w = tiptip_holder.outerWidth(); + var tip_h = tiptip_holder.outerHeight(); + var w_compare = Math.round((org_width - tip_w) / 2); + var h_compare = Math.round((org_height - tip_h) / 2); + var marg_left = Math.round(left + w_compare); + var marg_top = Math.round(top + org_height + opts.edgeOffset); + var t_class = ""; + var arrow_top = ""; + var arrow_left = Math.round(tip_w - 12) / 2; + + if(opts.defaultPosition == "bottom"){ + t_class = "_bottom"; + } else if(opts.defaultPosition == "top"){ + t_class = "_top"; + } else if(opts.defaultPosition == "left"){ + t_class = "_left"; + } else if(opts.defaultPosition == "right"){ + t_class = "_right"; + } + + var right_compare = (w_compare + left) < parseInt($(window).scrollLeft()); + var left_compare = (tip_w + left) > parseInt($(window).width()); + + if((right_compare && w_compare < 0) || (t_class == "_right" && !left_compare) || (t_class == "_left" && left < (tip_w + opts.edgeOffset + 5))){ + t_class = "_right"; + arrow_top = Math.round(tip_h - 13) / 2; + arrow_left = -12; + marg_left = Math.round(left + org_width + opts.edgeOffset); + marg_top = Math.round(top + h_compare); + } else if((left_compare && w_compare < 0) || (t_class == "_left" && !right_compare)){ + t_class = "_left"; + arrow_top = Math.round(tip_h - 13) / 2; + arrow_left = Math.round(tip_w); + marg_left = Math.round(left - (tip_w + opts.edgeOffset + 5)); + marg_top = Math.round(top + h_compare); + } + + var top_compare = (top + org_height + opts.edgeOffset + tip_h + 8) > parseInt($(window).height() + $(window).scrollTop()); + var bottom_compare = ((top + org_height) - (opts.edgeOffset + tip_h + 8)) < 0; + + if(top_compare || (t_class == "_bottom" && top_compare) || (t_class == "_top" && !bottom_compare)){ + if(t_class == "_top" || t_class == "_bottom"){ + t_class = "_top"; + } else { + t_class = t_class+"_top"; + } + arrow_top = tip_h; + marg_top = Math.round(top - (tip_h + 5 + opts.edgeOffset)); + } else if(bottom_compare | (t_class == "_top" && bottom_compare) || (t_class == "_bottom" && !top_compare)){ + if(t_class == "_top" || t_class == "_bottom"){ + t_class = "_bottom"; + } else { + t_class = t_class+"_bottom"; + } + arrow_top = -12; + marg_top = Math.round(top + org_height + opts.edgeOffset); + } + + if(t_class == "_right_top" || t_class == "_left_top"){ + marg_top = marg_top + 5; + } else if(t_class == "_right_bottom" || t_class == "_left_bottom"){ + marg_top = marg_top - 5; + } + if(t_class == "_left_top" || t_class == "_left_bottom"){ + marg_left = marg_left + 5; + } + tiptip_arrow.css({"margin-left": arrow_left+"px", "margin-top": arrow_top+"px"}); + tiptip_holder.css({"margin-left": marg_left+"px", "margin-top": marg_top+"px"}).attr("class","tip"+t_class); + + if (timeout){ clearTimeout(timeout); } + timeout = setTimeout(function(){ tiptip_holder.stop(true,true).fadeIn(opts.fadeIn); }, opts.delay); + } + + function deactive_tiptip(){ + opts.exit.call(this); + if (timeout){ clearTimeout(timeout); } + tiptip_holder.fadeOut(opts.fadeOut); + } + } + }); + } +})(jQuery); \ No newline at end of file diff --git a/public/javascripts/viewer.js b/public/javascripts/viewer.js new file mode 100644 index 0000000..d035457 --- /dev/null +++ b/public/javascripts/viewer.js @@ -0,0 +1,20 @@ +$(function() { + $('#home-tab').click(function () { + $(this).addClass('selected'); + $('#contact-tab').removeClass('selected'); + $('#home-page').stop(true, true).show(); + $('#contact-page').stop(true, true).hide(); + }); + $('#contact-tab').click(function () { + $(this).addClass('selected'); + $('#home-tab').removeClass('selected'); + $('#contact-page').stop(true, true).show(); + $('#home-page').stop(true, true).hide(); + }); + $('#contact-link').click(function () { + $('#contact-tab').addClass('selected'); + $('#home-tab').removeClass('selected'); + $('#contact-page').stop(true, true).show(); + $('#home-page').stop(true, true).hide(); + }); +}); \ No newline at end of file diff --git a/public/javascripts/widget.js b/public/javascripts/widget.js new file mode 100644 index 0000000..ecdc1e4 --- /dev/null +++ b/public/javascripts/widget.js @@ -0,0 +1,361 @@ +/*! + * Javascript sprintf + * http://www.webtoolkit.info/ + */ + +var sprintfWrapper = { + + init : function () { + + if (typeof arguments == "undefined") { return null; } + if (arguments.length < 1) { return null; } + if (typeof arguments[0] != "string") { return null; } + if (typeof RegExp == "undefined") { return null; } + + var string = arguments[0]; + var exp = new RegExp(/(%([%]|(\-)?(\+|\x20)?(0)?(\d+)?(\.(\d)?)?([bcdfosxX])))/g); + var matches = new Array(); + var strings = new Array(); + var convCount = 0; + var stringPosStart = 0; + var stringPosEnd = 0; + var matchPosEnd = 0; + var newString = ''; + var match = null; + + while (match = exp.exec(string)) { + if (match[9]) { convCount += 1; } + + stringPosStart = matchPosEnd; + stringPosEnd = exp.lastIndex - match[0].length; + strings[strings.length] = string.substring(stringPosStart, stringPosEnd); + + matchPosEnd = exp.lastIndex; + matches[matches.length] = { + match: match[0], + left: match[3] ? true : false, + sign: match[4] || '', + pad: match[5] || ' ', + min: match[6] || 0, + precision: match[8], + code: match[9] || '%', + negative: parseInt(arguments[convCount]) < 0 ? true : false, + argument: String(arguments[convCount]) + }; + } + strings[strings.length] = string.substring(matchPosEnd); + + if (matches.length == 0) { return string; } + if ((arguments.length - 1) < convCount) { return null; } + + var code = null; + var match = null; + var i = null; + + for (i=0; i= 1000) { + jQuery.getJSON(HOME + "/promos/" + id + "?callback=?", {t: now}, update); + last_poll = now; + } else if (cache) { + $timer.countdown(cache); + } + } + + function update(data) { + setOffset(data); + $timer.countdown(data); + $price.highlight(data.p, cache.p, formatPrice); + $bidder.highlight(data.u, cache.u); + if (data.w) { + clearInterval(ticker); + jQuery(".jh-bid-button", $wrapper).hide(); + jQuery('.jh-loser-button', $wrapper).show(); + jQuery('.jh-ended-text', $wrapper).show(); + jQuery('.jh-auction-timer', $wrapper).hide(); + } + cache = data; + } + + // Set the NTP offset. + function setOffset(data) { + var origtime = data.nt; + var offset = data.no; + var delay = (getNow() - origtime) / 2; + times[responses++ % 3] = offset - delay; // responses++ versus ++responses is important! + var sum = 0; + for (var i = 0; i < times.length; i++) { + sum += times[i]; + } + avgoffset = sum / times.length; + } + + function auction_url(id) { + var aff = (options.return_url ? options.return_url : HOME); + var url = HOME + "/auctions/" + id + "?auction_registration=true&affiliate=" + options.affiliate + "&categories=" + options.auctionCategories.join("-") + "&affiliate_url=" + encodeURI(aff); + return url; + } + + function homepage_url() { + var aff = (options.return_url ? options.return_url : HOME); + return HOME + "?affiliate=" + options.affiliate + "&categories=" + options.auctionCategories.join("-") + "&affiliate_url=" + encodeURI(aff) + } + + function main() { + jQuery.getScript("https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.6/jquery-ui.min.js"); + // Set some utilities + jQuery.fn.countdown = function (json) { + var ms = json.e * 1000 - fixTime(); + var remaining = ms; + var display; + var hours = Math.floor(remaining / 3600000); + remaining = remaining % 3600000; + var minutes = Math.floor(remaining / 60000); + remaining = remaining % 60000; + var seconds = Math.ceil(remaining / 1000); + if (seconds == 60) { + seconds = 0; + minutes++; + if (minutes == 60) { + minutes = 0; + hours++; + } + } + if (ms < 200) { + display = "checking..."; + } else if (ms <= 15000) { + display = '' + sprintf("%02d:%02d:%02d", hours, minutes, seconds) + ''; + } else { + display = sprintf("%02d:%02d:%02d", hours, minutes, seconds); + } + return this.html(display); + }; + jQuery.fn.highlight = function (current, cached, formatter, options) { + if (current !== cached) { + this.html(formatter ? formatter(current, options) : current).stop(true, true).effect("highlight", {color: "#fcd960"}, 3000); + } + return this; + }; + if (!options.widgetCategories) { + options.widgetCategories = options.categories; + } + if (!options.auctionCategories) { + options.auctionCategories = options.widgetCategories; + } + jQuery(function() { + $wrapper = jQuery("#justhaute-widget-wrapper, .justhaute-widget-wrapper"); + $wrapper.append("" + + "
    " + + "
    " + + "« Prev" + + "1 of ..." + + "Next »" + + "
    " + + "View All" + + "
    " + + "
    " + + "
    " + + "

    loading...

    " + + "

    Reg. Price: loading...

    " + + "
    " + + "
    " + + "" + + "
    " + + "
    " + + "
    loading...
    " + + "
    Ended!
    " + + "
    " + + "
    " + + "loading..." + + "
    " + + "
    " + + "loading..." + + "
    " + + "
    " + + "
    " + + "
    " + + "
    " + + "
    " + + "
    " + + "
    " + + "

    Previously sold to:

    " + + "

    for

    " + + "
    "); + $timer = jQuery(".jh-auction-timer", $wrapper); + $price = jQuery(".jh-auction-price", $wrapper); + $bidder = jQuery(".jh-auction-last-bidder", $wrapper); + jQuery(".jh-nav .jh-prev").click(function () { + if (num > 1) { + loadProduct(num - 1); + } + return false; + }); + jQuery(".jh-nav .jh-next").click(function () { + if (num < products.length) { + loadProduct(num + 1); + } + return false; + }); + jQuery.getJSON(HOME + "/promos?callback=?", {widgets: options.widgetCategories.join("-"), auctions: options.auctionCategories.join("-"), t: getNow()}, initializeProducts); + }); + } + +} \ No newline at end of file diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..bc706d3 --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,5 @@ +# See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file +# +# To ban all spiders from the entire site uncomment the next two lines: +#User-Agent: * +#Disallow: / diff --git a/public/stylesheets/.gitkeep b/public/stylesheets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/public/stylesheets/admin.css b/public/stylesheets/admin.css new file mode 100644 index 0000000..1ea63e3 --- /dev/null +++ b/public/stylesheets/admin.css @@ -0,0 +1,466 @@ +body#admin h2 { + text-indent: 0; + font: 1.75em "Helvetica Neue", Helvetica, Arial, sans-serif; + margin-bottom: 10px; +} +body#admin h2 span { + font-size: 0.8em; +} +/* + * ADMIN NAVIGATION + */ +body#admin #main-menu { + background: url(../images/header/nav-bg.png); + height: 40px; + margin-left: -5px; + width: 990px; + margin-bottom: 25px; +} +body#admin #main-menu li { + float: left; + border-right: #ccc; +} +body#admin #main-menu li a { + display: block; + padding: 0 20px; + margin: 5px 0; + height: 25px; + line-height: 25px; + color: #a19ba1; + font-size: 13px; + font-weight: bold; + border-right: 1px dotted #7c7c7c; + outline: 0 none; +} +body#admin #main-menu li a:hover { + text-decoration: none; + color: #fff; +} +body#admin #main-menu li.last { + float: right; +} +body#admin #main-menu li.last a { + border-right: 0 none; +} +/* + * ADMIN TABLES + */ +body#admin table { + margin-bottom: 15px; +} +body#admin table th { + border-bottom: 2px solid #ccc; + line-height: 1.4em; + font-size: 1.0em; + font-weight: bold; +} +body#admin table th.name { + width: 28%; +} +body#admin table td.label { + width: 80px; + padding-right: 10px; + font-weight: bold; + text-align: right; + vertical-align: top; + border: 0 none; + line-height: 1.5em; +} +body#admin table td.value { + border: 0 none; + line-height: 1.5em; +} +#product-admin table th.id { + width: 15%; +} +#product-admin table th.name { + width: 37%!important; +} +#product-admin table td.id { + padding-right: 1em; +} +#product-admin table td.name { + line-height: 1.3em; + padding-right: 1em; +} +#product-admin table th.price { + width: 10%; +} +.admin-page table th.edit, .admin-page table th.remove { + width: 5%; +} +#auction-admin table th.time { + width: 25%; +} +#auction-admin table th.price { + width: 10%; +} +.admin-page table td { + line-height: 3.0em; + border-bottom: 1px dotted #ddd; + font-size: 0.9em; +} +#category-admin .category .name { + line-height: 1.3em; + width: 50%; +} +/* + * ADMIN FORMS + */ +#product-form { + margin-bottom: 25px; +} +.admin-page .field label { + width: 150px; +} +.admin-page .field span { + font-size: 0.8em; + padding-left: 65px; +} +input.short { + width: 75px; +} +input.wide { + width: 300px; +} +#product-form textarea { + width: 660px; + height: 400px; + border: 1px solid #CDCED0; + font-size: 12px; + padding: 0.6em; + color: #808080; + overflow-y: scroll; +} +body#admin input[type="checkbox"] { + margin: 9px auto; +} +#product-form .main { + margin-bottom: 25px; +} +#product-form .secondary { + margin-bottom: 5px; +} +#product-form .picture { + float: left; +} +#product-form .summary { + float: left; +} +/* + ADMIN BUTTONS +*/ +/* BACK-EDIT-SHOW NAVIGATION LINKS */ +.admin-page .nav-links { + margin-bottom: 35px; +} +.admin-page .nav-links a { + float: left; + margin-right: 25px; +} +.admin-page .nav-links .button, .admin-page #ship-order .button { + height: 23px; + width: 103px; +} +.admin-page .nav-links .back { + background: url(../images/buttons/backarrow.png); +} +.admin-page .nav-links .show { + background: url(../images/buttons/showarrow.png); +} +.admin-page .nav-links #view-on-site { + background: url(../images/buttons/viewonsite.png); +} + +.admin-page .nav-links #feature-item { + background: url(../images/buttons/feature-item.png); +} + +.admin-page .nav-links .edit { + background: url(../images/buttons/editarrow.png); +} +/* ADD NEW ITEM BUTTON */ +.admin-page #add-new-item .button { + height: 23px; + width: 153px; + background: url(../images/buttons/admin-new-items.gif); +} +#product-admin #add-new-item .button { + background-position: 0 -25px; +} +#brands-admin #add-new-item .button { + background-position: 0 -50px; +} +#category-admin #add-new-item .button { + background-position: 0 -75px; +} +#coupon-admin #add-new-item .button { + background-position: 0 -100px; +} +.admin-page .field#ship-order p { + margin-bottom: 5px; +} +.admin-page #ship-order .button { + background: url(../images/buttons/ship.gif); + display: -moz-inline-stack; + display: inline-block; + zoom: 1; + *display: inline; + margin-left: 160px; +} +.admin-page .field#ship-order p strong { + font-size: 0.9em; +} +/* ADD ITEM BUTTON */ +.admin-page #add-item { + margin-bottom: 0; +} +.admin-page #add-item .button { + height: 34px; + width: 145px; + background: url(../images/buttons/add-item.gif); +} +.edit-page #add-item .button, .admin-page #update-item .button { + height: 34px; + width: 145px; + background: url(../images/buttons/edit-item.png); +} +.admin-page #add-item .button:hover, .edit-page #add-item .button:hover, .admin-page #update-item .button:hover { + background-position: 0 -34px; +} +.admin-page .actions { + margin-top: 25px; + padding-left: 157px; +} +/* ORDERS */ +#orders-admin h2 { + text-transform: capitalize; +} +#orders-admin th.id { + width: 13%; +} +#orders-admin th.username { + width: 18%; +} +#orders-admin th.contents { + width: 31%; +} +#orders-admin th.price { + width: 8%; +} +#orders-admin th.create-date { + width: 15%; +} +#orders-admin th.ship-date { + width: 15%; +} +#orders-admin th.amount, #orders-admin th.action { + width: 10%; +} +#orders-admin td.message, #orders-admin td.content { + line-height: 1.3em; +} +#orders-admin form { + color: #3B3B3B; + font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; +} +/* ACCOUNTS */ +#accounts-admin th.username { + width: 20%; +} +#accounts-admin th.join-date { + width: 17%; +} +#accounts-admin th.bids, #accounts-admin th.bonuses, #accounts-admin th.points { + width: 10%; +} +#accounts-admin table.user-basics { + float: left; + width: 45%; + margin-right: 55px; +} +#accounts-admin table.user-basics td, #accounts-admin table.user-details td { + padding-left: 10px; +} +#accounts-admin table colgroup.label { + width: 150px; + background: #f7f7f7; +} +#accounts-admin table colgroup.value { + padding-left: 10px; +} +#accounts-admin table.user-details { + float: left; + width: 40%; +} +#accounts-admin th.id { + width: 13%; +} +#accounts-admin th.date { + width: 15%; +} +#accounts-admin th.price, #accounts-admin th.status { + width: 10%; +} +.admin-page p.admin-hints { + font-size: 0.9em; + margin-bottom: 15px; + font-weight: bold; + color: #0088CC; +} +#account-order-history td.items { + padding: 5px 10px 5px 40px; +} +#account-order-history td.auction-win { + background: url(../images/icons/winner-trophy.png) no-repeat left center; +} +#account-order-history td.auction-buy-now { + background: url(../images/icons/buynow-trophy.png) no-repeat left center; +} +#account-order-history td.membershop-purchase { + background: url(../images/icons/discount-piggy.png) no-repeat left center; +} +#account-order-history td.bid-pack-purchase { + background: url(../images/icons/bids-single.png) no-repeat left center; +} +#account-order-history .order-history-hidden tr.declined, #account-order-history .order-history-hidden tr.void { + display: none; +} +#account-order-history tr.declined, #account-order-history tr.void { + background: #fae2e2; +} +#accounts-admin #show-void-declined { + font-weight: bold; + font-size: 13px; +} +#accounts-admin #show-void-declined:hover { + cursor: pointer; +} +/* AUCTIONS */ +#auction-admin p.auction-details { + margin-bottom: 3px; +} +#auction-admin p.auction-details strong { + display: -moz-inline-stack; + display: inline-block; + zoom: 1; + *display: inline; + width: 100px; + text-align: right; + margin-right: 5px; +} +/* PRODUCTS */ +#product-admin table#product-show td.label { + width: 120px; +} +table#product-show td.value ul, table#product-show td.value ol { + list-style-position: inside; +} +table#product-show td.value ul { + list-style-type: disc; +} +table#product-show td.value p, table#product-show td.value ul, table#product-show td.value ol { + line-height: 1.4em; + margin-bottom: 15px; +} +/* COUPONS */ +#coupon-admin th.code { + width: 22%; +} +#coupon-admin th.ending-time { + width: 18%; +} +#coupon-admin th.uses-left { + width: 15%; +} +#coupon-admin .field span { + padding-left: 5px; +} +#coupon-admin .field input#coupon_bonuses { + width: 60px; +} +/* ORDERS */ +#orders-admin table.cart-price { + width: 20%; + float: left; + margin-right: 25px; +} +#orders-admin table.cart-price .pink-1 { + font-weight: bold; +} +#orders-admin table.user-cart { + width: 45%; + float: left; +} +#orders-admin .main-product-image { + float: left; + margin-top: -130px; + box-shadow: 0 0 7px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 0 7px rgba(0, 0, 0, 0.2); + -webkit-box-shadow: 0 0 7px rgba(0, 0, 0, 0.2); +} +#orders-admin .main-product-image img { +} +#orders-admin .orders-admin-show .block-first { + margin-bottom: 0; +} +/* ANALYTICS */ +#analytics-admin select#content { + padding-bottom: 0.6em; + min-height: 0; +} +/* ADMIN BUTTONS */ +.orange-button, .blue-button { + font-family: "Helvetica Neue", Helvetica, Arial,sans-serif; + font-size: 0.9em; + border-color: #dc45df; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + padding: 0.35em 0.5em; + background: -webkit-gradient(linear, left top, left bottom, from(#f38c41), to(#cc6215)); + background: -moz-linear-gradient(-90deg, #f38c41, #cc6215); + text-shadow: 0 -1px 0 #974c15; + color: #fff; + display: inline-block; + margin-right: 5px; +} +.blue-button { + background: -webkit-gradient(linear, left top, left bottom, from(#22aae9), to(#1c85c1)); + background: -moz-linear-gradient(-90deg, #22aae9, #1c85c1); + text-shadow: 0 -1px 0 #23668c; +} +.orange-button:hover, .blue-button:hover { + text-decoration: none; +} +a.orange-button, a.blue-button { + padding: 0.45em 0.7em; + font-weight: bold; +} +a.positive-admin-button, a.negative-admin-button { + font-size: 0; + text-indent: -9999px; + display: block; + outline: 0 none; + height: 25px; + width: 60px; + background: url(../images/buttons/pos-neg-admin-btn.png) no-repeat; +} +a.negative-admin-button { + background-position: 0 -35px; +} +/* CATEGORIES */ +#category-admin input { + float: left; + margin-right: 5px; + line-height: 32px; +} +#category-admin input[type="submit"] { + margin: 4px 0; +} +#category-admin table.categories { + width: 60%; +} +#export-as-xml { + font-size: 0.8em; + margin-bottom: 25px; +} \ No newline at end of file diff --git a/public/stylesheets/base.css b/public/stylesheets/base.css new file mode 100644 index 0000000..baa008a --- /dev/null +++ b/public/stylesheets/base.css @@ -0,0 +1,1070 @@ +/* + * Copyright 2010 Expedient Shopping, Inc. + * Not to be copied or distributed without the written consent of Expedient Shopping, Inc. + */ + +/* + * STYLE RESETS + */ +html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, h7, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, del, dfn, font, img, ins, kbd, q, s, samp, +sub, sup, tt, var, dd, dl, dt, li, ol, ul, form, fieldset, input, textarea, label, +table, legend, caption, tbody, tfoot, thead, tr, th, td{ + font-family: inherit; + font-weight: inherit; + font-style: inherit; + font-size: 100%; + text-align: left; + margin: 0; + padding: 0; +} +.clearboth { + clear: both; +} +.clearfix:after, .clearfix-auto:after { + content: " "; + display: block; + height: 0; + clear: both; + visibility: hidden; +} +.clearfix { + display: inline-block; + width: 100%; +} +.clearfix-auto { + display: inline-block; +} +.inline { + display: -moz-inline-stack; + display: inline-block; + zoom: 1; + *display: inline; +} +img { + border: 0 none; +} +ul { + list-style: none; +} +table { + width: 100%; + border-collapse: collapse; +} +input[type="submit"] , button { + border: 0px none; + color: #fff; + font-weight: bold; + text-align: center; + background-color: #000; + outline: 0px none; +} +input[type="submit"]:hover , button:hover { + cursor: pointer; +} +textarea { + border: 1px solid #cdced0; + color: #808080; + font-size: 12px; + padding: 7px; + width: 436px; + height: 200px; +} +/* + * ALIGNMENTS + */ +.left { + float: left; +} +.right { + float: right; +} +.alignL { + text-align: left; +} +.alignR { + text-align: right; +} +.alignC { + text-align: center; +} +/* + * TYPOGRAPHY + * + * ORANGE: #EF7A25 + * RED: #E50F42; + * LIGHT BLUE: #4CA1F3 + * BLUE: #0088CC + * + * @FONT-FACE: Andika + * + */ +.auction-timer .ending { + color: #e50f42; +} +#auctions-index .auction-timer .ending { + color: #e50f42; +} +.blue { + color: #0088CC; +} +a { + color: #0088CC; + text-decoration: none; +} +a:hover { + text-decoration: underline; + cursor: pointer; +} +h2 { + margin-bottom: 20px; + color: #ef7a25; + height: 29px; + text-indent: -9999px; + font: 1.7em/1.0em "Helvetica Neue", Helvetica, Arial, sans-serif; +} +h3 { + font: 1.4em/1.1em "Helvetica Neue", Helvetica, Arial, sans-serif; + color: #5c5c5c; +} +h1 a:hover, h2 a:hover, h3 a:hover { + text-decoration: none; +} +#container #content input, #container #content a, #container #content li, #container #content h1, #container #content h2, #container #content h3 { + background-repeat: no-repeat; +} +.button { + font-size: 0; + text-indent: -9999px; + display: block; + outline: 0 none; +} +/* + * CONTENT BLOCKS + */ +.block-first, .block-middle { + margin-bottom: 55px; +} +.block-last { + +} + + + + +/* + * FORMS STYLES + * + * COLOR: #808080; + * BORDERS: #CDCED0; + * + */ +form { + font-family: Verdana, Helvetica, sans-serif; + color: #808080; +} +input[type="text"], input[type="password"], select { + padding: 0.6em; + font-size: 12px; + font-weight: bold; + border: 1px solid #CDCED0; + color: #808080; +} +input[type="text"], input[type="password"] { + width: 232px; +} +input[type="checkbox"] { + width: 15px; +} +.small { + width: 100px; + margin-right: 10px; +} +.medium { + width: 120px; +} +.large { + width: 330px; +} +form .field { + margin-bottom: 10px; +} +form .input { + margin-bottom: 15px; +} +form .field label { + float: left; + width: 60px; + text-align: right; + margin-right: 10px; + line-height: 32px; + color: #5c5c5c; + font-size: 0.9em; + text-transform: capitalize; + font-family: Verdana, Helvetica, sans-serif; + display: -moz-inline-stack; + display: inline-block; + zoom: 1; + *display: inline; +} +form.address-form p.state { + float: left; +} +form.address-form p.zip { + float: left; +} +form.address-form p.zip input { + widtH: 60px; +} +form.address-form p.zip label { + width: 40px; +} + + + + + + + + + + + + +/* + * TOP LEVEL WRAPPERS + */ +html { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + margin: 0; + padding: 0; + background: #F0F0F0; + color: #3B3B3B; +} +body { + position: relative; +} +.padded { + padding: 0 20px; +} +#main-wrapper { + width: 990px; + margin: 0 auto; + padding-bottom: 15px; +} +#container { + width: 980px; + margin: 0 auto; + padding: 0 5px; + background: url(../images/wrapper/main-wrapper.png) repeat-y; + position: relative; +} +#container-bottom { + height: 15px; + background: url(../images/wrapper/footer-wrapper.png) no-repeat scroll center bottom; +} +#content { + padding-bottom: 70px; + min-height: 300px; + height: auto!important; +} +.box-shadow { + -moz-box-shadow: 0 1px 3px #CCC; + -webkit-box-shadow: 0 1px 3px #CCC; + -khtml-box-shadow: 0 1px 3px #CCC; + box-shadow: 0 1px 3px #CCC; + border: 1px solid #ccc; +} +/* FOOTER */ +#footer-wrapper { + margin: 0 auto; + width: 980px; + border-top: 1px solid #e3e3e3; +} +#footer { + padding: 20px 10px 20px 10px; + width: 950px; +} +#footer p { + text-align: center; +} +#footer a { + outline: 0 none; +} +#footer ul { + text-align: center; + margin-bottom: 10px; +} +#footer ul li { + margin-right: 15px; + display: -moz-inline-stack; + display: inline-block; + zoom: 1; + *display: inline; +} +#footer ul#merchant-icons li { + line-height: 80px; +} +#footer ul#merchant-icons li img { + vertical-align: middle; +} + + + + + + + + + + + + + + + +/* + * HEADER + */ +#header { + padding-top: 10px; + margin-bottom: 15px; +} +#header #logo-area h1 { + float: left; +} +#header #logo-area h1 a { /* CUSTOMIZE THIS PER AFFILIATE */ + display: block; + width: 195px; + height: 40px; + background: url(../images/header/logo.gif) no-repeat; + text-indent: -9999px; + font-size: 0; +} +#header #logo-area #social-media-affiliate { + margin-left: 33px; + float: left; +} +#header #logo-area .twitter-follow { + float: left; +} +#header #logo-area .facebook-like { + float: left; + margin-left: 5px; +} +#header #logo-area { + margin-left: 20px; +} +#header #logo-area a { + outline-color: #c7c7c7; +} +/* + * LOGIN & LOGOUT + */ +/* + * TOP NAV + */ +#top-login { + position: absolute; + top: 5px; + right: 15px; + font-size: 12px; + line-height: 22px; + padding: 0; + z-index: 999; +} +#login-tab { + text-align: right; + font-size: 0.9em; +} +#login-tab #toggle-node, #login-tab #logout-node { + padding: 2px 8px; + background: #4ca1f3; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + -khtml-border-radius: 5px; + border-radius: 5px; + font-weight: bold; + color: #fff; + display: -moz-inline-stack; + display: inline-block; + zoom: 1; + *display: inline; +} +#login-tab #button .expanded { + background: #c7c7c7; + -moz-border-radius: 5px 5px 0 0; + -webkit-border-radius: 5px 5px 0 0; + -khtml-border-radius: 5px 5px 0 0; + border-radius: 5px 5px 0 0; + color: #3B3B3B; +} +#login-tab #button .expanded span { + background-image: url(../images/msc/expanded-arrow.png); +} +#login-tab #toggle-node:hover, #login-tab #button .expanded:hover { + cursor: pointer; +} +#login-tab #toggle-node span { + padding: 0 20px 0 0; + display: -moz-inline-stack; + display: inline-block; + zoom: 1; + *display: inline; + background: url(../images/msc/login-arrow.png) no-repeat center right; +} +#login-tab #logout-node span { + padding: 0 20px 0 0; + display: -moz-inline-stack; + display: inline-block; + zoom: 1; + *display: inline; + background: url(../images/msc/logout-arrow.png) no-repeat center right; +} +#login-tab #logout-node span a { + color: #fff; +} +#login-body { + display: none; + width: 220px; + padding: 13px 10px; + background: #fff; + border: 5px solid #c7c7c7; + -moz-border-radius: 5px 0 5px 5px; + -moz-box-shadow: 0 3px 3px #d8d8d8; + -webkit-border-radius: 5px 0 5px 5px; + -webkit-box-shadow: 0 3px 3px #d8d8d8; + -khtml-border-radius: 5px 0 5px 5px; + -khtml-box-shadow: 0 3px 3px #d8d8d8; + border-radius: 5px 0 5px 5px; + box-shadow: 0 3px 3px #d8d8d8; +} +#login-body label { + text-align: left; + line-height: 16px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} +#login-body input, .login-forgot-password { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} +#login-body input[type="text"], #login-body input[type="password"] { + padding: 0.4em; + width: 207px; +} +#login-body #account_session_remember_me { + margin-left: 0; + margin-right: 0; /* FOR TOP LOGIN ONLY */ +} + +form .field label[for="account_session_remember_me"], form .field label[for="shipping-address-toggle-node"] { + float: none; + width: auto; + line-height: 1.0em; + text-align: left; + text-transform: none; + margin: 0; +} +.login-remember-me-wrapper .actions { + float: left; +} +.login-remember-me-wrapper .signin { + margin-right: 15px; +} +.login-remember-me-wrapper .remember-me { + padding-top: 3px; + font-size: 11px; +} +#login-body #login-submit { + margin-left: 0; + width: 60px; + height: 26px; + background: url(../images/buttons/login-top.png); + display: block; + text-shadow: 0 -1px 0 #2270bd; +} +#login-body #login-submit:hover { + +} +.login-forgot-password { + font-size: 0.9em; +} +/* + * USER CREDITS + */ +ul#user-credits-overview { + float: left; + margin: 4px 0; +} +ul#user-credits-overview li { + float: left; + padding: 0 6px; + line-height: 15px; + border-right: 1px solid #c7c7c7; +} +ul#user-credits-overview li.last { + border-right: 0 none; + text-transform: uppercase; + font-size: 10px; +} +ul#user-credits-overview .credits, ul#user-credits-overview .bonuses, ul#user-credits-overview .points { + font-weight: bold; +} +ul#user-credits-overview .points { + color: #808080; +} +/* + * USER CREDITS MAIN + */ +#user-credits-main { + font-size: 13px; + background: #F7F7F7; + color: #3b3b3b; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + box-shadow: 0 0 7px rgba(0,0,0,0.2); + -moz-box-shadow: 0 0 7px rgba(0,0,0,0.2); + -moz-box-shadow: 0 0 7px rgba(0,0,0,0.2); + border: 2px solid #C7C7C7; + padding: 5px; + position: fixed; + right: 50px; + bottom: 10px; + z-index: 9999; +} +#user-credits-main ul li { + float: left; + margin-right: 45px; +} +#user-credits-main ul li div { + line-height: 25px; +} +#user-credits-main ul li img, #user-credits-main ul li span, #user-credits-main ul li strong { + vertical-align: middle; +} +#user-credits-main ul li span { + font-weight: bold; +} +#user-credits-main ul li strong { + font-size: 1.2em; +} +#user-credits-main ul li strong.points-count { + font-size: 1.0em; +} +#user-credits-main ul li.last { + margin-right: 0; +} +#user-credits-main ul li a.button { + height: 30px; + width: 80px; + background: url(../images/buttons/buy-bids-small.png); +} +#user-credits-main .latency { + display: inline-block; + width: 32px; + height: 26px; + background: #F7F7F7 url(../images/icons/connection.png) no-repeat 0 0; + text-indent: -9999px; + cursor: pointer; +} +#user-credits-main .latency.conn-fair { + background-position: 0 -26px; +} +#user-credits-main .latency.conn-poor { + background-position: 0 -52px; +} +#user-credits-main .credits-count, #user-credits-main .bonuses-count { + color: #0088CC; +} +#user-credits-main .points-count { + color: #808080; +} +/* + * LOGIN PAGE + */ +#account_session_remember_me { + margin-left: 70px; + margin-right: 5px; +} +#login-submit { + margin-left: 70px; + width: 80px; + height: 30px; + background: url(../images/buttons/login.png); +} +.form-page input[type="text"], .form-page input[type="password"]{ + width: 58%; +} + + + + + + + + + + + +/* + * MAIN SPLASH IMAGE + */ +#splash { + margin-bottom: 25px; +} +#splash .get-started { + height: 150px; + background: url(../images/header/firstbargain-how-to.jpg) no-repeat; + text-indent: -9999px; + font-size: 0; +} +#splash .get-started h2, #splash .get-started p { + min-height: 0; + height: 0; + margin: 0; +} +#splash .get-started .button-area { + float: right; + margin: 30px 15px 0 0; + width: 190px; +} +#splash .get-started a { + width: 190px; + height: 46px; + background: url(../images/buttons/splash-get-started.png) no-repeat; +} +#splash p.explanation { + height: 15px; + background: url(../images/header/get-started-text.png) no-repeat center center; + margin-bottom: 10px; +} +#splash .current-user p.explanation { + height: 30px; + background-image: url(../images/header/buy-bids-text.png); +} +#splash .get-started .current-user a { + background-position: 0 -50px; +} + + + + + + + + + + +/* + * PROMO SLIDESHOW + */ +#promo-slideshow { + margin: -10px -20px 20px -20px; + height: 320px; + width: 980px; + background: url(../images/slideshow/promo-slideshow-bg.png); +} +#promo-slideshow .wrapper { + padding: 10px 20px; + width: auto; +} +#promo-slideshow #slideshow-content { + width: 620px; height: 300px; + float: left; +} +/* CONTENT */ +#promo-slideshow #slideshow-content div { + height: 300px; + text-indent: -9999px; + font-size: 0; + display: none; +} +#promo-slideshow #slideshow-content h2, #promo-slideshow #slideshow-content h3, #promo-slideshow #slideshow-content p { + min-height: 0; + height: 0; + margin: 0; +} +#promo-slideshow #slideshow-content .how-to { + background: url(../images/slideshow/how-to.png); +} +#promo-slideshow #slideshow-content .how-to .button { + margin: 232px 0 0 335px; + width: 176px; + height: 46px; + background: url(../images/buttons/register-now.png); +} +#promo-slideshow #slideshow-content .featured { + background-repeat: no-repeat; + padding: 20px; + height: 260px; + background-position: 5px 40px; +} +#promo-slideshow #slideshow-content .featured h2, #promo-slideshow #slideshow-content .featured p { + text-indent: 0; +} +#promo-slideshow #slideshow-content .featured h2 { + font-size: 26px; + margin-bottom: 35px; + height: 24px; +} +#promo-slideshow #slideshow-content .featured p { + font-size: 13px; + color: #44a8da; + margin: 0 5px 0 280px; + height: 150px; + text-align: justify; +} +#promo-slideshow #slideshow-content .featured .button { + margin-left: 335px; + width: 182px; + height: 45px; + background: url(../images/buttons/learn-more-large.png); +} +#promo-slideshow #slideshow-content .featured-fallback { + background: url(../images/slideshow/featured/040711.png); +} +#promo-slideshow #slideshow-content .featured-fallback .button { + margin: 222px 0 0 335px; + width: 182px; + height: 45px; + background: url(../images/buttons/learn-more-large.png); +} +#promo-slideshow #slideshow-content .bargains { + background: url(../images/slideshow/bargains.png); +} +#promo-slideshow #slideshow-content .tips { + background: url(../images/slideshow/tips.png); +} +#promo-slideshow #slideshow-content .tips .button { + margin: 200px 0 0 20px; + width: 182px; + height: 45px; + background: url(../images/buttons/learn-more-large.png); +} +#promo-slideshow #slideshow-content .referral { + background: url(../images/slideshow/referral.png); +} +#promo-slideshow #slideshow-content .referral .button { + margin: 200px 0 0 20px; + width: 182px; + height: 45px; + background: url(../images/buttons/invite-friends-large.png); +} +#promo-slideshow #slideshow-content .facebook { + background: url(../images/slideshow/facebook.png); +} +#promo-slideshow #slideshow-content .facebook .button { + margin: 180px 0 0 20px; + width: 210px; + height: 40px; + background: url(../images/buttons/visit-facebook-button.png); +} +/* NAVIGATION */ +#promo-slideshow #slideshow-navigation { + width: 321px; height: 300px; + margin-right: -1px; + float: left; +} +#promo-slideshow #slideshow-navigation li div { + line-height: 58px; + margin-bottom: 0px; + font-size: 1.2em; + font-weight: bold; + border-bottom: 1px solid #e7e7e7; + border-top: 1px solid #fff; +} +#promo-slideshow #slideshow-navigation li div span { + padding-left: 70px; + display: block; +} +#promo-slideshow #slideshow-navigation li div:hover { + cursor: pointer; +} +#promo-slideshow #slideshow-navigation li div.first { + height: 59px; + line-height: 59px; + border-top: 0 none; +} +#promo-slideshow #slideshow-navigation li div.current { + color: #0c0c0c; + border-top: 1px solid #cecece; + background: url(../images/slideshow/nav-current-bg.png) repeat-x; +} +#promo-slideshow #slideshow-navigation li div.first.current { + border-top: 0 none; + background: url(../images/slideshow/nav-first-current-bg.png) no-repeat; +} +#promo-slideshow #slideshow-navigation li.how-to span { + background: url(../images/icons/notepad.png) 20px center no-repeat; +} +#promo-slideshow #slideshow-navigation li.featured span { + background: url(../images/icons/star.png) 20px center no-repeat; +} +#promo-slideshow #slideshow-navigation li.featured-fallback span { + background: url(../images/icons/star.png) 20px center no-repeat; +} +#promo-slideshow #slideshow-navigation li.bargains span { + background: url(../images/icons/us-dollar.png) 20px center no-repeat; +} +#promo-slideshow #slideshow-navigation li.tips span { + background: url(../images/icons/trophy.png) 20px center no-repeat; +} +#promo-slideshow #slideshow-navigation li.referral span { + background: url(../images/icons/speaker.png) 20px center no-repeat; +} +#promo-slideshow #slideshow-navigation li.facebook span { + background: url(../images/icons/facebook.png) 20px center no-repeat; +} + + + + + + + + + + + + + + + + + + + + +/* + * NAVIGATION BAR + */ +#navigation { + background: url(../images/header/nav-bg.png); + height: 40px; + margin-left: -5px; + width: 990px; +} +#navigation h1 { + height: 90px; + float: left; + margin-right: 80px; + margin-left: 20px; +} +#navigation ul { + float: right; + padding-right: 5px; +} +#navigation ul li { + float: right; +} +#navigation ul li a { + display: block; + padding: 0 20px; + margin: 5px 0; + height: 25px; + line-height: 25px; + color: #a19ba1; + font-size: 13px; + font-weight: bold; + border-right: 1px solid #7c7c7c; + outline: 0 none; +} +#navigation ul li a:hover { + text-decoration: none; + color: #fff; +} +#navigation ul li.current a { + color: #fff; +} +#navigation ul li.last a { + border-right: 0 none; + padding-right: 30px; +} +#navigation ul li.facebook-link, #navigation ul li.facebook-link a, #navigation ul li.invite-link, #navigation ul li.invite-link a { + float: left; + border-right: 0 none; +} +#navigation ul li.facebook-link a { + background: url(../images/header/facebook-link.png) no-repeat; + width: 27px; + height: 27px; + padding: 0; + margin: 4px 0 4px 0; +} +#navigation ul li.invite-link a { + background: url(../images/header/invite-link.png) no-repeat; + height: 35px; + width: 135px; + padding: 0; + margin: 0 5px 0 30px; +} + + + + + + + + + + + + +/* + * PAGINATION + */ +.pagination a, .pagination em, .pagination span { + border: 1px solid #0088CC; + padding: 0.3em 0.7em; + display: -moz-inline-stack; + display: inline-block; + zoom: 1; + *display: inline; + font-size: 0.85em; + font-weight: bold; + outline: 0 none; +} +.pagination a { + color: #0088CC; +} +.pagination em { + color: #fff; + background: #0088CC; +} +.pagination .disabled { + font-weight: normal; + color: #808080; + border-color: #a0a0a0; +} +.pagination em { + font-style: normal; +} + + + + + + + +/* + * SIDE BAR MENU & WRAPPERS + */ +.sidebar #main-menu { + width: 215px; + float: left; + margin-right: 25px; + background: url(../images/wrapper/dashboard-main-menu-bg.png) repeat-y; + min-height: 600px; + height: auto!important; +} +.sidebar #main-menu li { + line-height: 3.0em; + padding-right: 10px; + margin-bottom: 0px; + font-size: 13px; + font-weight: bold; +} +.sidebar #main-menu li.current { + background: url(../images/wrapper/dashboard-nav-arrow.png) no-repeat scroll 100% 0; +} +.sidebar #main-menu li.first { + margin-top: 45px; +} +.sidebar #main-menu li.last { + margin-bottom: 185px; + border-bottom: 0px none; +} +.sidebar #main-menu a, .sidebar #main-menu span { + color: #0088CC; + display: block; + padding-left: 10px; + border-bottom: 1px solid #eee; + outline-color: #ccc; +} +.sidebar #main-menu span:hover { + cursor: pointer; +} +.sidebar #main-menu a:hover { + text-decoration: none; +} +/* CURRENT PAGE WRAPPERS */ +.sidebar .current-page { + width: 700px; + float: left; + height: auto!important; +} + + + + + + + + + + + + + + + + + + + + + + + +/* + * HOLIDAY PROMOTIONS + */ +#valentines-promotion { + height: 272px; + width: 960px; + background: url(../images/special-offers/valentines-day/valentine.jpg) no-repeat; + margin-top: -22px; + margin-right: -20px; + margin-bottom: 25px; +} +#valentines-promotion a { + height: 40px; + width: 210px; + background: url(../images/special-offers/valentines-day/visit-facebook-button.png) no-repeat; + float: right; + margin: 225px 290px 0 0; +} +#apple-promotion { + height: 270px; + width: 960px; + background: url(../images/special-offers/apple-day/apple-day-banner.jpg) no-repeat; + margin-top: -22px; + margin-right: -20px; + margin-bottom: 25px; +} +#apple-promotion a { + height: 40px; + width: 210px; + background: url(../images/special-offers/apple-day/visit-facebook-button.png) no-repeat; + float: right; + margin: 210px 400px 0 0; +} + + + + + + + + + + + +/* + * ERROR DIALOG + */ +.error-modal-dialog.ui-dialog { + position: fixed!important; + top: 25%!important; +} \ No newline at end of file diff --git a/public/stylesheets/dashboard.css b/public/stylesheets/dashboard.css new file mode 100644 index 0000000..24f5b33 --- /dev/null +++ b/public/stylesheets/dashboard.css @@ -0,0 +1,541 @@ +/* + * DASHBOARD TITLES + */ +h2.my-credits { + background: url(../images/text/my-credits.png); +} +h2.redeem-auctions { + background: url(../images/text/redeem-auctions.png); +} +h2.my-wins { + background: url(../images/text/my-wins.gif); +} +h2.buynow-auctions { + background: url(../images/text/buynow-auctions.png); +} +h2.watchlist { + background: url(../images/text/watchlist.png); + margin-bottom: 35px; +} +h2.edit-account { + background: url(../images/text/edit-account-information.png); +} +h2.saved-addresses { + background: url(../images/text/saved-addresses.png); +} +h2.invitations { + background: url(../images/text/invitations.png); +} +h2.redeem-coupon-codes { + background: url(../images/text/redeem-coupon-codes.png); + margin-bottom: 50px; +} +h2.new-address { + background: url(../images/text/new-address.png); +} +h2.your-order-history { + background: url(../images/text/your-order-history.png); +} + + + + + + + + + + + +/* + * DASHBOARD FORMS + */ +form.dashboard-form .field label { + width: 135px; +} +form.dashboard-form .actions { + margin-left: 145px; +} +form.dashboard-form { + margin-top: 70px; +} +form.dashboard-form .button { + background-position: 0px -34px; +} +/* EDIT ACCOUNT */ +form#update-account .button { + background: url(../images/buttons/submit.png); + width: 80px; + height: 30px; +} +form#update-account .checkbox-agreements { + font-size: 0.9em; + margin-bottom: 25px; +} +form#update-account .checkbox-agreements input { + float: left; + margin-top: 2px; + margin-left: 45px; +} +form#update-account .checkbox-agreements p { + padding-left: 65px; + color: #5C5C5C; +} +/* ADDRESS FORM */ +#account-page .address-listing { + font-size: 0.9em; + padding-bottom: 20px; + margin-bottom: 20px; + width: 300px; + border-bottom: 1px solid #f0f0f0; +} +#account-page .back { + width: 103px; + height: 23px; + background: url(../images/buttons/backarrow.png); +} +#account-page p.new-address { + margin-bottom: 50px; +} +#account-page .add-new-address { + width: 153px; + height: 23px; + background: url(../images/buttons/add-new-address.gif); +} +form#new-address .button { + background: url(../images/buttons/save-address.gif); + width: 130px; + height: 34px; +} +#new-address .example { + font-size: 0.8em; +} +#addresses .seperator { + margin: 10px 0px 10px; + height: 2px; + background: #808080; + width: 40%; +} + + + + + + +/* DASHBOARD AUCTION BUTTONS */ +#redeemable-auctions a.button, #buynow-auctions a.button, #watchlist-auctions .button { + width: 90px; + height: 35px; + background: url(../images/buttons/bid-small.gif); +} + + + + + + +/* + * DASHBOARD TABLES + */ +#account-page table { + margin-top: 25px; + margin-bottom: 10px; +} +#account-page table td { + border-bottom: 1px dotted #c7c7c7; + padding: 10px 0; +} +#account-page table th { + border-bottom: 2px solid #ccc; + line-height: 2.0em; + font-size: 11px; + font-weight: bold; +} +#account-page #buy-now-popup table { + margin: 0; +} +#account-page #buy-now-popup td { + border-bottom: 0 none; + padding: 0; +} +#account-page #buy-now-popup tr.bonuses-used td { + border-bottom: 1px solid #C7C7C7 +} +/* REDEEMABLE AUCTIONS */ +#redeemable-auctions { + margin-bottom: 10px; +} +#redeemable-auctions th.image, #buynow-auctions th.image { + width: 80px; +} +#redeemable-auctions th.auction-price, #buynow-auctions th.auction-price { + width: 100px; +} +#redeemable-auctions th.shipping-price, #buynow-auctions th.shipping-price { + width: 90px; +} +#redeemable-auctions th.total-price, #buynow-auctions th.total-price { + width: 100px; +} +#redeemable-auctions th.redeem, #buynow-auctions th.redeem{ + width: 90px; +} +#redeemable-auctions a.button { + background-position: 0 -160px; +} +#buynow-auctions a.button { + background-position: 0 -240px; +} +#redeemable-auctions .free, #buynow-auctions .free { + font-size: 12px; +} +/* WATCHLIST */ +#watchlist-auctions .image { + width: 80px; +} +#watchlist-auctions .title { + +} +#watchlist-auctions .timer { + width: 90px; + text-align: center; +} +#watchlist-auctions .bidder .auction-last-bidder { + padding: 1px 5px; +} +#watchlist-auctions .timer .winner-text { + display: none; + color: #ef7a25; +} +#watchlist-auctions .timer .ended-text { + display: none; +} +#watchlist-auctions .price { + width: 70px; + text-align: center; +} +#watchlist-auctions .price .auction-price { + padding: 1px 5px; +} +#watchlist-auctions .bidder { + width: 120px; + text-align: center; +} +#watchlist-auctions .bid-button { + width: 90px; + text-align: center; +} +#watchlist-auctions .winner-button { + display: none; +} +#watchlist-auctions .loser-button { + display: none; +} +#watchlist-auctions td.price { + color: #33BC33; +} +#watchlist-auctions td.bidder { + font-size: 12px; +} +#watchlist-auctions .button { + margin: 0 auto; +} +#watchlist-auctions .winner-button .button { + background-position: 0 -160px; +} +#watchlist-auctions .loser-button .button { + background-position: 0 -200px; +} +#watchlist-auctions .delete { + text-align: right; + width: 50px; +} +#watchlist-auctions td.delete a { + font-size: 11px; +} +/* ORDER-HISTORY TABLE */ +#order-history-icon-legend { + height: 40px; + background: url(../images/icons/user-order-history-legend.jpg) no-repeat; +} +#account-order-history .date { + width: 140px; + padding-left: 10px; +} +#account-order-history .items { + +} +#account-order-history .price { + width: 100px; + text-align: center; +} +#account-order-history .status { + width: 100px; + text-align: center; +} +#account-order-history td.date { + font-size: 1.1em; +} +#account-order-history td.date span, #account-order-history td.items span.order-id { + display: block; + margin-top: 5px; + font-size: 0.8em; + font-weight: bold; +} +#account-order-history td.items { + padding: 7px 10px 7px 40px; +} +#account-order-history td.items span.order-id { + font-size: 0.85em; +} +#account-order-history td.auction-win { + background: url(../images/icons/winner-trophy.png) no-repeat left center; +} +#account-order-history td.auction-buy-now { + background: url(../images/icons/buynow-trophy.png) no-repeat left center; +} +#account-order-history td.membershop-purchase { + background: url(../images/icons/discount-piggy.png) no-repeat left center; +} +#account-order-history td.bid-pack-purchase { + background: url(../images/icons/bids-single.png) no-repeat left center; +} +#account-order-history td.status { + font-size: 0.9em; +} +#account-order-history .order-history-hidden tr.declined, #account-order-history .order-history-hidden tr.void { + display: none; +} +#account-order-history tr.declined, #account-order-history tr.void { + background: #f7f7f7; +} +#account-order-history #show-void-declined { + font-weight: bold; + font-size: 13px; + width: 200px; + text-align: center; + padding: 7px; + background: #1c85c1; + color: #fff; + border-color: #dc45df; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + background: -webkit-gradient(linear, left top, left bottom, from(#22aae9), to(#1c85c1)); + background: -moz-linear-gradient(-90deg, #22aae9, #1c85c1); + text-shadow: 0 -1px 0 #23668c; + display: inline-block; + margin-right: 5px; +} +#account-order-history #show-void-declined:hover { + cursor: pointer; +} +/* ORDER HISTORY LEGEND */ +#order-history-key h3 { + font-size: 1.0em; + font-weight: bold; +} +#order-history-key dl { + border-top: 1px solid #ccc; + padding-top: 10px; + font-size: 0.9em; + margin-top: 3px; +} +#order-history-key dt { + float: left; + color: #51b222; +} +#order-history-key dt.error { + color: #f22E2E; +} +#order-history-key dt.hold { + color: #EF7A25; +} +#order-history-key dd { + padding-left: 100px; + margin-bottom: 10px; +} +/* MY WINS */ +table#auction-monthly-wins { + width: auto; +} +table#auction-monthly-wins tr { + border: 0 none; +} +table#auction-monthly-wins td { + border: 0 none; + padding: 0 15px 15px 0; +} +table#auction-monthly-wins p { + padding: 10px; + width: 70px; + height: 65px; + background: url(../images/wrapper/my-wins-wrapper.gif); +} +table#auction-monthly-wins img { + width: 70px; + height: 65px; +} + + + + + + +/* + * DASHBOARD OVERVIEW + */ +#account-page .current-page span.credits, #account-page .current-page span.bonuses { + font-weight: bold; + color: #0088CC; +} +#account-page .current-page span.points { + font-weight: bold; + color: #808080; +} + + + + + + + + +/* + * REDEEM COUPONS PAGE + */ +#redeem-coupons-page p { + margin-bottom: 35px; +} +#redeem-coupons-page form label { + width: auto; +} +#redeem-coupons-page form input[type="text"] { + width: 200px; + float: left; +} +#redeem-coupons-page form input[type="submit"] { + float: left; + height: 23px; + margin: 4px 5px; + width: 138px; + background: url(../images/buttons/redeem-coupon.png); +} + + + + + + + + + + + +/* + * INVITES PAGE + */ +/* TABS */ +#invites-page #invites-tabs { + margin-bottom: 15px; +} +#invites-page #invites-tabs ul { + height: 27px; + line-height: 27px; + background: url(../images/wrapper/invites-tabs/bg.png) repeat-x; +} +#invites-page #invites-tabs ul li { + float: left; + font-size: 0; + text-indent: -9999px; + height: 27px; +} +#invites-page #invites-tabs ul li:hover { + cursor: pointer; +} +#invites-tabs ul li#invite-friends-tab { + background: url(../images/wrapper/invites-tabs/invite-friends.png) no-repeat; + width: 122px; +} +#invites-tabs ul li#your-invites-tab { + background: url(../images/wrapper/invites-tabs/your-invites.png) no-repeat; + width: 105px; + margin-left: 5px; +} +#invites-page #invites-tabs ul li.selected { + background-position: 0 -27px; +} +#invites-page #your-invites { + display: none; +} +/* TEXT AND FORMS */ +#invites-page .invite-explanation, #invites-page .link-explanation { + height: 25px; + font-size: 0; + text-indent: -9999px; + background: url(../images/text/invite-explanation.gif) no-repeat; + margin-bottom: 25px; +} +#invites-page form { + margin-bottom: 55px; +} +#invites-page .link-explanation { + background: url(../images/text/invite-link-explanation.gif) no-repeat; + margin-bottom: 10px; +} +#invite-friends .invitation-link { + font-size: 1.1em; + text-align: center; + font-family: "Cambria", Georgia, "Times New Roman", serif; + color: #EF7A25; +} +#invites-page form label { + width: 160px; +} +#invites-page form input[type="text"] { + width: 260px; +} +#invites-page form .field span { + font-size: 0.8em; +} +#invites-page form .actions input { + margin-left: 170px; +} +#invites-page form input[type="submit"] { + background: url(../images/buttons/submit.png); + height: 30px; + width: 80px; +} +#your-invites th.made-purchase { + width: 130px; +} +#your-invites th.bonus-bids { + width: 100px; +} + + + + + + + + + + + +/* + * RESEND VERIFICATION + */ +.resend-verification-email { + padding: 10px 10px 7px 10px; + background: #f3ebd7; + margin-bottom: 35px; + font-size: 0.9em; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; +} +.resend-verification-email p { + margin-bottom: 3px; +} +.resend-verification-email a { + font-weight: bold; +} diff --git a/public/stylesheets/external/appconsumer.css b/public/stylesheets/external/appconsumer.css new file mode 100644 index 0000000..8bf9b24 --- /dev/null +++ b/public/stylesheets/external/appconsumer.css @@ -0,0 +1,10 @@ +#header #logo-area h1 a { /* CUSTOMIZE THIS PER AFFILIATE */ + width: 222px; + height: 46px; + background: url(../../images/external/appconsumer/logo.gif) no-repeat; +} +#header #logo-area .powered-by { + width: 135px; + height: 20px; + background: url(../../images/external/powered-by.gif) no-repeat; +} diff --git a/public/stylesheets/external/dailymakeover.css b/public/stylesheets/external/dailymakeover.css new file mode 100644 index 0000000..4b52e59 --- /dev/null +++ b/public/stylesheets/external/dailymakeover.css @@ -0,0 +1,10 @@ +#header #logo-area h1 a { /* CUSTOMIZE THIS PER AFFILIATE */ + width: 137px; + height: 55px; + background: url(../../images/external/dailymakeover/logo.gif) no-repeat; +} +#header #logo-area .powered-by { + width: 135px; + height: 20px; + background: url(../../images/external/powered-by.gif) no-repeat; +} diff --git a/public/stylesheets/external/widget-default.css b/public/stylesheets/external/widget-default.css new file mode 100644 index 0000000..4ff6fe4 --- /dev/null +++ b/public/stylesheets/external/widget-default.css @@ -0,0 +1,294 @@ +/* RESETS */ +#justhaute-widget-wrapper a, +#justhaute-widget-wrapper a:hover, +.justhaute-widget-wrapper a, +.justhaute-widget-wrapper a:hover +{ + text-decoration: none; +} +a#justhaute-widget-link img { + border: 0 none; +} +a#justhaute-widget-link { + width: 222px; + display: block; + margin: 0 auto; + outline: 0 none; + padding-bottom: 40px; +} +.jh-product-container +{ + width: 220px; + color: #3B3B3B; + background: #ffffff; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + -khtml-border-radius: 5px; + border-radius: 5px; + -moz-box-shadow: 0 0 3px #e0e0e0; + border: 1px solid #e0e0e0; + font: 12px "Helvetica Neue", Helvetica, Arial, sans-serif; +} +/* + * PRODUCT CONTAINER + */ +#justhaute-widget-wrapper .jh-product-container, +.justhaute-widget-wrapper .jh-product-container +{ + width: 220px; + padding-bottom: 7px; + margin: 0 auto; +} +#justhaute-widget-wrapper .jh-product-container .jh-image, +.justhaute-widget-wrapper .jh-product-container .jh-image +{ + height: 204px; + overflow: hidden; + text-align: center; +} +/* FONT-RESETS */ +#justhaute-widget-wrapper p, +#justhaute-widget-wrapper h3, +#justhaute-widget-wrapper div, +#justhaute-widget-wrapper table, +.justhaute-widget-wrapper p, +.justhaute-widget-wrapper h3, +.justhaute-widget-wrapper div, +.justhaute-widget-wrapper table +{ + text-shadow: none; + text-indent: 0; + font-style: none; + font-weight: normal; + text-align: center; + margin: 0; + padding: 0; +} +/* NAVIGATION */ +#justhaute-widget-wrapper .jh-nav:after, +.justhaute-widget-wrapper .jh-nav:after +{ + content: " "; + display: block; + height: 0; + clear: both; + visibility: hidden; +} +#justhaute-widget-wrapper .jh-nav, +.justhaute-widget-wrapper .jh-nav +{ +font: 11px/13px Arial,Helvetica,sans-serif; +width: 220px; +margin: 0 auto; +margin-bottom: 3px; +} +#justhaute-widget-wrapper .jh-nav a, +.justhaute-widget-wrapper .jh-nav a +{ +font: 11px/13px Arial,Helvetica,sans-serif; +padding: 0 0.15em; +text-decoration: none; +-moz-border-radius: 2px; +} +#justhaute-widget-wrapper .jh-nav a:hover, +.justhaute-widget-wrapper .jh-nav a:hover +{ +text-decoration: none; +} +#justhaute-widget-wrapper .jh-nav .jh-paging, +.justhaute-widget-wrapper .jh-nav .jh-paging +{ +float: left; +font: 11px/13px Arial,Helvetica,sans-serif; +} +#justhaute-widget-wrapper .jh-nav a.jh-prev, +.justhaute-widget-wrapper .jh-nav a.jh-prev, +#justhaute-widget-wrapper .jh-nav a.jh-next, +.justhaute-widget-wrapper .jh-nav a.jh-next +{ +border: 1px solid #e7e7e7; +color: #808080; +background: #eeeeee; +} +#justhaute-widget-wrapper .jh-nav a.jh-prev, +.justhaute-widget-wrapper .jh-nav a.jh-prev +{ +margin-right: 3px; +} +#justhaute-widget-wrapper .jh-nav a.jh-next, +.justhaute-widget-wrapper .jh-nav a.jh-next +{ +margin-left: 3px; +} +#justhaute-widget-wrapper .jh-nav #jh-all, +.justhaute-widget-wrapper .jh-nav #jh-all +{ +float: right; +border: 1px solid #83bcf1; +background: #bbdbf9; +} +/* TITLE */ +#justhaute-widget-wrapper .jh-product-container h3, +.justhaute-widget-wrapper .jh-product-container h3 +{ + color: #0088CC; +} +#justhaute-widget-wrapper .jh-product-container p, +#justhaute-widget-wrapper .jh-product-container div, +.justhaute-widget-wrapper .jh-product-container p, +.justhaute-widget-wrapper .jh-product-container div +{ + text-align: center; +} +#justhaute-widget-wrapper .jh-product-container .jh-title, +.justhaute-widget-wrapper .jh-product-container .jh-title +{ + width: 100%; +} +#justhaute-widget-wrapper .jh-product-container .jh-title h3, +.justhaute-widget-wrapper .jh-product-container .jh-title h3 +{ + padding: 5px 5px 0 5px; + font-size: 14px; + line-height: 14px; + font-weight: bold; +} +#justhaute-widget-wrapper .jh-product-container .jh-title p, +.justhaute-widget-wrapper .jh-product-container .jh-title p +{ + color: #808080; + font-size: 11px; +} +/* TIMER */ +#justhaute-widget-wrapper .jh-product-container .jh-timer-container, +.justhaute-widget-wrapper .jh-product-container .jh-timer-container +{ + font-size: 2.0em; +} +#justhaute-widget-wrapper .jh-product-container .jh-timer-container, +#justhaute-widget-wrapper .jh-product-container .jh-timer-container a, +.justhaute-widget-wrapper .jh-product-container .jh-timer-container, +.justhaute-widget-wrapper .jh-product-container .jh-timer-container a, +{ + color: #3B3B3B; +} +#justhaute-widget-wrapper .jh-product-container .jh-timer-container .jh-ending, +.justhaute-widget-wrapper .jh-product-container .jh-timer-container .jh-ending +{ + color: #0088CC; +} +#justhaute-widget-wrapper .jh-product-container .jh-timer-container .jh-ended-text, +.justhaute-widget-wrapper .jh-product-container .jh-timer-container .jh-ended-text +{ + display: none; +} +/* PRICE */ +#justhaute-widget-wrapper .jh-product-container .jh-price-container, +.justhaute-widget-wrapper .jh-product-container .jh-price-container +{ + color: #33bc33; + font-size: 1.6em; +} +#justhaute-widget-wrapper .jh-product-container .jh-price-container a, +.justhaute-widget-wrapper .jh-product-container .jh-price-container a +{ + color: #33bc33; +} +#justhaute-widget-wrapper .jh-product-container .jh-auction-price, +.justhaute-widget-wrapper .jh-product-container .jh-auction-price +{ + padding: 0 7px; +} +/* LAST BIDDER */ +#justhaute-widget-wrapper .jh-product-container .jh-last-bidder-container, +.justhaute-widget-wrapper .jh-product-container .jh-last-bidder-container +{ + margin-bottom: 3px; + color: #808080; +} +#justhaute-widget-wrapper .jh-product-container .jh-last-bidder-container a, +.justhaute-widget-wrapper .jh-product-container .jh-last-bidder-container a +{ + color: #808080; +} +#justhaute-widget-wrapper .jh-product-container .jh-auction-last-bidder, +.justhaute-widget-wrapper .jh-product-container .jh-auction-last-bidder +{ + padding: 0 7px; +} +/* BUTTONS */ +#justhaute-widget-wrapper .jh-product-container .jh-buttons div, +.justhaute-widget-wrapper .jh-product-container .jh-buttons div +{ + width: 90px; + height: 35px; + background: url(../../images/buttons/bid-small.gif); + margin: 0 auto; +} +#justhaute-widget-wrapper .jh-product-container .jh-bid-button:hover, +.justhaute-widget-wrapper .jh-product-container .jh-bid-button:hover +{ + cursor: pointer; + background-position: 0 -320px; +} +#justhaute-widget-wrapper .jh-product-container .jh-buttons .jh-loser-button, +.justhaute-widget-wrapper .jh-product-container .jh-buttons .jh-loser-button +{ + display: none; + background-position: 0 -200px; +} +#justhaute-widget-wrapper .jh-product-container .jh-loser-button:hover, +.justhaute-widget-wrapper .jh-product-container .jh-loser-button:hover +{ + cursor: pointer; +} +/* + * LAST WENT FOR + */ +#justhaute-widget-wrapper .jh-previous-auction, +.justhaute-widget-wrapper .jh-previous-auction +{ + padding: 0 5px 10px 5px; + width: 210px; + margin: 0 auto; +} +#justhaute-widget-wrapper .jh-previous-auction div#jh-savings-tag, +.justhaute-widget-wrapper .jh-previous-auction div#jh-savings-tag +{ + float: left; + width: 50px; + height: 70px; + padding: 25px 0 0 0; + text-align: center; + background: url(../../images/labels/sale-tag.png) no-repeat; + color: #3B3B3B; +} +#justhaute-widget-wrapper .jh-previous-auction span.jh-previous-savings, +.justhaute-widget-wrapper .jh-previous-auction span.jh-previous-savings +{ + font-size: 1.5em; +} +#justhaute-widget-wrapper .jh-previous-auction span.jh-previous-price, +.justhaute-widget-wrapper .jh-previous-auction span.jh-previous-price +{ + font-size: 1.1em; + font-weight: bold; +} +#justhaute-widget-wrapper .jh-previous-auction p, +.justhaute-widget-wrapper .jh-previous-auction p +{ + font-size: 12px; + line-height: 14px; + text-align: left; + padding-left: 60px; +} +#justhaute-widget-wrapper p.jh-previously-sold-for, +.justhaute-widget-wrapper p.jh-previously-sold-for +{ + padding: 10px 0 7px 60px; +} +#justhaute-widget-wrapper .jh-previous-auction p.jh-previous-winner, +.justhaute-widget-wrapper .jh-previous-auction p.jh-previous-winner +{ + font-weight: bold; +} \ No newline at end of file diff --git a/public/stylesheets/flat.css b/public/stylesheets/flat.css new file mode 100644 index 0000000..6fd6404 --- /dev/null +++ b/public/stylesheets/flat.css @@ -0,0 +1,801 @@ +/* + * TWO COLUMN LAYOUTS --- THE SIZE AND MARGINS OF CONTAINERS MUST BE WRITTEN HERE + */ +.left-column-1, .left-column-2, .left-column-3, .right-column-1, .right-column-2, .right-column-3, .left-column-4 { + float: left; + min-height: 395px; + height: auto!important; +} +.right-column-1, .right-column-2, .right-column-3, .right-column-4 { + float: right; +} +/* LEFT COLUMNS */ +.left-column-1 { + padding: 40px 0; + width: 52%; + background: url(../images/wrapper/shadow-right.png) repeat-y right center; + min-height: 505px; + height: auto!important; +} +.left-column-2 { + width: 48%; + margin-left: 15px; +} +.left-column-3 { + width: 54%; +} +.left-column-4 { + width: 50%; + padding: 40px 0; +} +/* RIGHT COLUMNS */ +.right-column-1 { + padding-top: 40px; + width: 40%; +} +.right-column-2 { + width: 46%; +} +.right-column-3 { + width: 42%; +} +.right-column-4 { + width: 44%; + padding-right: 4%; + height: auto!important; +} + + + + + + + + + + + +/* + * LOGIN PAGE + */ +#login-page h2 { + margin-bottom: 50px; +} +h2.sign-in { + background: url(../images/text/sign-in-to-your-account.gif); +} +h2.new-to-website { + background: url(../images/text/new-to-website.gif); +} +#login-page .field label { + +} +#login-page .password-reset { + margin-left: 70px; + font-size: 0.8em; + color: #7c7c7c; + margin-bottom: 15px; +} +#register-for-free, #signup-for-free, #buy-bid-credits { + width: 154px; + height: 35px; + background: url(../images/buttons/get-started.gif); +} +#register-for-free { + background-position: 0 -80px; +} +#buy-bid-credits { + background-position: 0 -40px; +} + + + + + + + + + + +/* + * ACTIVATION PAGE + */ +h2.activate-your-account { + background: url(../images/text/activate-your-account.gif); + margin-bottom: 50px; +} +#account-activation p { + margin-bottom: 35px; +} +#account-activation form .button { + background: url(../images/buttons/activate-account.gif); + width: 140px; + height: 35px; +} + + + + + + + + + + +/* + * PASSWORD RESET + */ +h2.reset-your-password { + background: url(../images/text/reset-your-password.gif); + margin-bottom: 50px; +} +#reset-password-page p { + margin-bottom: 35px; +} +#reset-password-page label { + width: 140px; +} +#reset-password-page form input[type="text"] { + float: left; + width: 200px; +} +#reset-password-page form .button { + background: url(../images/buttons/reset-password.png); + width: 138px; + height: 23px; + margin: 4px 5px 4px 5px; + float: left; +} + + + + + + + + + + + + + + +/* + * STATIC PAGES TYPOGRAPHY + */ +h2.about-us { + background: url(../images/text/about-us.gif); +} +h2.contact-us { + background: url(../images/text/contact-us.gif); +} +h2.faq { + background: url(../images/text/faq.gif); + margin-bottom: 35px; +} +h2.privacy-policy { + background: url(../images/text/privacy-policy.gif); +} +h2.terms-of-service { + background: url(../images/text/terms-of-service.gif); +} +h2.how-to-play { + background: url(../images/text/how-to-play.gif); + margin-bottom: 55px; +} +h2.return-policy { + background: url(../images/text/return-policy.gif); +} +h2.guarantee { + background: url(../images/text/guarantee.gif); +} +h2.bidding-tips { + background: url(../images/text/bidding-tips.gif); +} +h2.site-rules { + background: url(../images/text/site-rules.gif); +} +#flat-page .unit { + margin-bottom: 25px; +} +#flat-page p, #flat-page h4, #flat-page dl, #flat-page ul, #flat-page ol { + font-size: 1.0em; +} +#flat-page h3 { + border-bottom: 1px solid #c7c7c7; + margin-bottom: 5px; +} +#flat-page h4 { + margin-bottom: 5px; + color: #0088CC; + font: 1.15em "Helvetica Neue", Helvetica, Arial, sans-serif; +} +#flat-page p { + line-height: 1.4em; + margin-bottom: 15px; +} +.right-column-2 p, .right-column-3 p { + padding-right: 75px; + margin-bottom: 35px; +} +#flat-page address { + margin-bottom: 13px; + padding-left: 25px; +} +#flat-page span.help-link { + color: #2f2f2f; +} + + + + + + + + + +/* + * ABOUT PAGE + */ +#flat-page #about-tabs { + margin-bottom: 15px; +} +#flat-page #about-tabs ul { + height: 27px; + line-height: 27px; + background: url(../images/wrapper/about-tabs/bg.png) repeat-x; +} +#flat-page #about-tabs ul li { + float: left; + font-size: 0; + text-indent: -9999px; + height: 27px; + margin-bottom: 0; +} +#flat-page #about-tabs ul li:hover { + cursor: pointer; +} +#about-tabs ul li#overview-tab { + background: url(../images/wrapper/about-tabs/overview-bg.png) no-repeat; + width: 105px; +} +#about-tabs ul li#team-tab { + background: url(../images/wrapper/about-tabs/team-bg.png) no-repeat; + width: 105px; + margin-left: 5px; +} +#about-tabs ul li#advisory-tab { + background: url(../images/wrapper/about-tabs/advisory-bg.png) no-repeat; + width: 150px; + margin-left: 5px; +} +#flat-page #about-tabs ul li.selected { + background-position: 0 -27px; +} +#about-overview { + +} +#about-team, #about-advisory { + display: none; +} +#about-team span.position { + font-weight: normal; + color: #808080; +} +.blurb { + width: 90%; +} + + + + + + + + + +/* + * HOW TO PLAY + */ +body#tutorial h3 { + border-bottom: 0 none; +} +body#tutorial #how-to-menu { + margin-bottom: 35px; +} +body#tutorial #how-to-menu ul { + height: 27px; + line-height: 27px; + background: url(../images/wrapper/about-tabs/bg.png) repeat-x; +} +body#tutorial #how-to-menu ul li { + float: left; + font-size: 0; + text-indent: -9999px; + height: 27px; + margin-bottom: 0; + width: 105px; +} +body#tutorial #how-to-menu ul li a { + display: block; + outline: 0 none; + color: #dedede; + width: 105px; + height: 27px; +} +body#tutorial #how-to-menu ul li:hover { + cursor: pointer; +} +#how-to-menu ul li#auctions-tab { + background: url(../images/wrapper/how-to-tabs/auctions.gif) no-repeat; + margin-left: 318px; +} +#how-to-menu ul li#rewards-tab { + background: url(../images/wrapper/how-to-tabs/rewards.gif) no-repeat; + margin-left: 5px; +} +#how-to-menu ul li#guarantee-tab { + background: url(../images/wrapper/how-to-tabs/guarantee.gif) no-repeat; + margin-left: 5px; +} +body#tutorial #how-to-menu ul li.current { + background-position: 0 -27px; +} +#how-to-play-page #how-to-overview { + padding-top: 250px; + background: url(../images/how-to-play/steps.jpg) no-repeat; + margin-bottom: 20px; +} +#how-to-play-page #how-to-overview ul { + width: 290px; + padding-left: 10px; + margin-right: 20px; + float: left; +} +#how-to-play-page #how-to-overview ul.last { + margin-right: 0; + width: 280px; +} +#how-to-play-page #how-to-overview li { + color: #808080; + margin-bottom: 13px; + padding-left: 10px; + font: 13px "Helvetica Neue", Helvetica, Arial, sans-serif; +} +#how-to-play-page #get-started-now { + padding: 0 10px 0 0; + margin-bottom: 45px; +} +#how-to-play-page #sign-up, #how-to-play-page #buy-bids { + float: right; + margin-right: 15px; +} +#how-to-play-page #sign-up h3 , #how-to-play-page #buy-bids h3 { + margin-bottom: 0; +} +#how-to-play-page #sign-up h3 { + line-height: 36px; +} +#how-to-play-page #buy-bids h3 { + line-height: 0.9em; + margin-bottom: 0.1em; +} +#how-to-play-page #buy-bids p { + margin-bottom: 0; +} +#how-to-play-page ol { + margin-left: 45px; +} +#how-to-play-page ol li { + margin-bottom: 5px; +} +#how-to-play-page .steps h3 { + font-style: normal; +} +#member-rewards-page .how-to-cell { + margin-bottom: 20px; +} +#member-rewards-page .how-to-cell dl.explanation { + padding-left: 405px; + padding-top: 20px; +} +#member-rewards-page .how-to-cell dl.explanation dt { + text-transform: uppercase; + font-weight: bold; + color: #EF7A25; +} +#member-rewards-page .how-to-cell dl.explanation dd { + margin-bottom: 15px; + color: #5C5C5C; +} + + + + + + + + +/* + * FAQ PAGES + */ +#faq-page-index .row { + margin-bottom: 35px; +} +#faq-page-index .column { + float: left; + width: 220px; + margin-right: 20px; +} +#faq-page-index .column.last { + margin-right: 0; +} +#faq-page-index .column .button { + width: 220px; + height: 40px; + margin-bottom: 10px; +} +#faq-page-index .column.new-users .button { + background: url(../images/faq/new-to-firstbargain.png); +} +#faq-page-index .column.auctions .button { + background: url(../images/faq/auctions.png); +} +#faq-page-index .column.account .button { + background: url(../images/faq/account.png); +} +#faq-page-index .column.shipping .button { + background: url(../images/faq/shipping.png); +} +#faq-page-index .column.payment .button { + background: url(../images/faq/payment.png); +} +#faq-page-index .column ul li { + margin: 0 0 8px 20px; + font-size: 0.95em; +} +#faq-page-index .column .button.revealed { + background-position: 0 -50px; +} +#faq-page-show h2 { + text-indent: 0; + font-size: 2.0em; +} +#faq-page-show h3 { + width: 90%; +} +#faq-page-show p { + width: 80%; +} +#faq-page-show p { + margin-left: 20px; +} + + + + + + +/* + * FAQ + */ +#flat-page .faq-block { + margin-bottom: 20px; +} +#flat-page .faq-block p { + margin-bottom: 0; +} +#flat-page .faq-block h3 { + padding-left: 15px; + background: url(../images/msc/minus.gif) no-repeat left center; + font-size: 1.4em; +} +#flat-page .faq-block h3:hover { + cursor: pointer; +} +#flat-page .faq-hidden p { + display: none; +} +#flat-page .faq-hidden h3 { + background: url(../images/msc/plus.gif) no-repeat left center; + border-bottom: 0; +} + + + + + + + + + +/* + * CONTACT FORM + */ +#how-to-contact { + margin-bottom: 25px; +} +#how-to-contact p.blurb { + margin-bottom: 7px; +} +p.ccbill-contact { + margin-left: 15px; +} +#recaptcha_widget_div { + margin: 0 0 15px 110px; + width: 450px; +} +#contact-form .field label { + width: 100px; +} +#contact-form .actions { + margin-left: 110px; +} +#contact-form .actions input { + background: url(../images/buttons/submit.png); + width: 80px; + height: 30px; +} + + + + + + + +/* + * BIDDING TIPS & SITE RULES + */ +#tips-rules-wrapper { + float: right; + margin-right: -25px; +} +#tips-rules-wrapper #bidding-tips-link { + width: 150px; + height: 35px; + background: url(../images/buttons/bidding-tips.png); + margin-bottom: 5px; +} +#tips-rules-wrapper #site-rules-link { + width: 150px; + height: 35px; + background: url(../images/buttons/site-rules.png); +} +/* BIDDING TIPS */ +#bidding-tips-page { + background: url(../images/how-to-play/bidding-tips.jpg) bottom right no-repeat; +} +#bidding-tips-page .wrapper { + width: 60%; +} +/* SITE RULES */ +#site-rules-page { +} +#site-rules-page ol { + list-style: decimal inside; + font-weight: bold; + margin-left: 25px; + width: 90%; +} +#site-rules-page ol li { + margin-bottom: 15px; +} + + + + + + + + + +/* + * PENNY PROMO + */ +.penny-promo h1#logo { + width: 195px; + height: 40px; + background: url(../images/header/logo.gif) no-repeat; + text-indent: -9999px; + font-size: 0; +} +.penny-promo #splash { + height: 302px; + background: url(../images/promo/main-splash.jpg) no-repeat; + margin-bottom: 20px; +} +.penny-promo #ourprice { + height: 53px; + background: url(../images/promo/ourprices.jpg) center center no-repeat; + margin-bottom: 35px; +} +.penny-promo #firstbargain-vs-ebay { + height: 321px; + background: url(../images/promo/firstbargain-vs-ebay.jpg) no-repeat; + margin-bottom: 20px; +} +.penny-promo #penny-revolution { + height: 452px; + background: url(../images/promo/penny-revolution.jpg) no-repeat; + margin-bottom: 20px; +} +.penny-promo #firstbargain-savings { + height: 40px; + width: 990px; + margin-left: -25px; + background: url(../images/promo/firstbargain-savings.png) no-repeat; +} +.penny-promo #savings-banner { + width: 950px; + height: 268px; + background: url(../images/promo/savings-banner.jpg) no-repeat; + margin-bottom: 55px; +} +.penny-promo #ended-auctions-text { + height: 40px; + width: 990px; + margin-left: -25px; + background: url(../images/promo/ended-auctions-text.png) no-repeat; + margin-bottom: 10px; +} +.penny-promo #ended-auctions { + height: 400px; + width: 980px; + margin-left: -20px; + background: url(../images/promo/ended-auctions.jpg) no-repeat; + margin-bottom: 35px; +} +.penny-promo #live-auctions-text { + height: 40px; + width: 990px; + margin-left: -25px; + background: url(../images/promo/live-auctions-text.png) no-repeat; + margin-bottom: 10px; +} +.penny-promo #live-auctions { + margin-bottom: 55px; +} +.penny-promo #thousands-satisfied { + height: 77px; + background: url(../images/promo/thousands-satisfied.jpg) no-repeat; + margin-bottom: 55px; +} +.penny-promo #testimonials { + float: left; + height: 700px; + width: 460px; + background: url(../images/promo/testimonials.jpg) no-repeat; +} +/* + * PROMO REGISTRATION FORM + */ +.penny-promo #registration-wrapper { + margin-bottom: 55px; +} +.penny-promo #registration-form { + float: right; + color: #fff; +} +.penny-promo #registration-form .header { + height: 86px; + width: 460px; + background: url(../images/promo/signup-wrap-01.jpg) no-repeat; +} +.penny-promo #registration-form .body { + padding: 45px 20px 55px 30px; + width: 410px; + background: url(../images/promo/signup-wrap-02.jpg); +} +.penny-promo #registration-form .footer { + height: 24px; + width: 460px; + background: url(../images/promo/signup-wrap-03.jpg) no-repeat; +} +.penny-promo #registration-form label { + color: #fff; +} +.penny-promo #registration-form .field label { + font-weight: bold; + width: 140px; +} +.penny-promo #registration-form input[type="text"], .penny-promo #registration-form input[type="password"], .penny-promo #registration-form select { + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; +} +.penny-promo #registration-form #username-explanation { + margin-left: 150px; +} +.penny-promo #registration-form #username-explanation p { + color: #fff; + font-size: 0.8em; + margin-bottom: 10px; +} +.penny-promo #registration-form #username-explanation p.last { + margin-bottom: 25px; +} +.penny-promo #registration-form #dob { + margin-bottom: 45px; +} +.penny-promo #registration-form .checkbox-agreements { + font-size: 0.9em; + margin-bottom: 15px; +} +.penny-promo #registration-form #tos-agreement { + margin-bottom: 45px; +} +.penny-promo #registration-form .checkbox-agreements input { + float: left; + margin-top: 2px; + margin-left: 25px; +} +.penny-promo #registration-form .checkbox-agreements p { + padding-left: 45px; + color: #fff; +} +.penny-promo #registration-form .actions input { + margin-left: 35px; + height: 82px; + width: 347px; + background: url(../images/promo/signup-button.png) no-repeat; +} +.penny-promo #penny-quotes { + height: 243px; + background: url(../images/promo/penny-quotes.jpg) no-repeat; +} +/* + * PROMO REGISTRATION FORM ERROR MESSAGES + */ +.penny-promo #registration-form #errorExplanation { + border: 1px solid #524f3e; + color: #8f5d5d; +} +.penny-promo #registration-form #errorExplanation p { + font-weight: bold; + color: #ee4545; +} +.penny-promo #registration-form #errorExplanation ul li { + color: #e5e4d9; +} + + + + + + + + + +/* + * PROMO LANDING PAGE + */ +#promo-landing-page #penny-head { + height: 230px; + background: url(../images/promo/penny-head.jpg) no-repeat; + margin-bottom: 20px; +} +#promo-landing-page #scroll-out { + margin-bottom: 55px; +} + + + + + + + + + +/* + * PROMO REGISTRATION PAGE + */ +#registration-page #scroll-out { + margin-bottom: 25px; +} +#registration-page #penny-head { + width: 990px; + margin-left: -25px; + height: 184px; + background: url(../images/promo/penny-head-2.png) no-repeat; + margin-bottom: 35px; +} \ No newline at end of file diff --git a/public/stylesheets/fonts.css b/public/stylesheets/fonts.css new file mode 100644 index 0000000..80e9185 --- /dev/null +++ b/public/stylesheets/fonts.css @@ -0,0 +1,11 @@ +/* + * CUSTOM FONT DECLARATIONS GO HERE + */ + +@font-face { + font-family: 'Andika'; + src: url('../fonts/embed/AndBasR-webfont.eot'); + src: local('firstbarginfonts'), url('../fonts/embed/AndBasR-webfont.woff') format('woff'), url('../fonts/embed/AndBasR-webfont.ttf') format('truetype'), url('../fonts/embed/AndBasR-webfont.svg#webfont8NZgWOv8') format('svg'); + font-weight: normal; + font-style: normal; +} \ No newline at end of file diff --git a/public/stylesheets/ie.css b/public/stylesheets/ie.css new file mode 100644 index 0000000..fd1d78c --- /dev/null +++ b/public/stylesheets/ie.css @@ -0,0 +1,10 @@ +.clearfix { + zoom: 1; + *display: block; +} +.clearfix-auto { + display: -moz-inline-stack; + display: inline-block; + zoom: 1; + *display: inline; +} \ No newline at end of file diff --git a/public/stylesheets/ie7.css b/public/stylesheets/ie7.css new file mode 100644 index 0000000..75707ad --- /dev/null +++ b/public/stylesheets/ie7.css @@ -0,0 +1,23 @@ +#register-page #account_terms_of_service { + margin: 0; + padding: 0; +} +#register-page .field label[htmlFor="account_terms_of_service"] { + width: 380px; +} +form .field label[htmlFor="account_session_remember_me"], form .field label[htmlFor="account_terms_of_service"], form .field label[htmlFor="shipping-address-toggle-node"] { + float: none; + width: auto; + line-height: 1.0em; + text-align: left; + text-transform: none; + margin: 0; +} +select { + padding: 0.6em; + font-size: 12px; + font-weight: bold; + border: 1px solid #CDCED0; + color: #808080; +} + diff --git a/public/stylesheets/jqueryui.css b/public/stylesheets/jqueryui.css new file mode 100755 index 0000000..853e439 --- /dev/null +++ b/public/stylesheets/jqueryui.css @@ -0,0 +1,573 @@ +/* + * jQuery UI CSS Framework 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Theming/API + */ + +/* Layout helpers +----------------------------------*/ +.ui-helper-hidden { display: none; } +.ui-helper-hidden-accessible { position: absolute !important;} +.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } +.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } +.ui-helper-clearfix { display: inline-block; } +/* required comment for clearfix to work in Opera \*/ +* html .ui-helper-clearfix { height:1%; } +.ui-helper-clearfix { display:block; } +/* end clearfix */ +.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } + + +/* Interaction Cues +----------------------------------*/ +.ui-state-disabled { cursor: default !important; } + + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } + + +/* Misc visuals +----------------------------------*/ + +/* Overlays */ +.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } + + +/* + * jQuery UI CSS Framework 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Theming/API + * + * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS,%20Tahoma,%20Verdana,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=03_highlight_soft.png&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=02_glass.png&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=03_highlight_soft.png&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=08_diagonals_thick.png&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=08_diagonals_thick.png&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=01_flat.png&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px + */ + + +/* Component containers +----------------------------------*/ +.ui-widget { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1.1em; } +.ui-widget .ui-widget { font-size: 1em; } +.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1em; } +.ui-widget-content { border: 1px solid #dddddd; background: #eeeeee url(../images/jquery-ui-theme/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top repeat-x; color: #333333; } +.ui-widget-content a { color: #333333; } +.ui-widget-header { border: 1px solid #e78f08; background: #f6a828 url(../images/jquery-ui-theme/ui-bg_gloss-wave_35_f6a828_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; } +.ui-widget-header a { color: #ffffff; } + +/* Interaction states +----------------------------------*/ +.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #cccccc; background: #f6f6f6 url(../images/jquery-ui-theme/ui-bg_glass_100_f6f6f6_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1c94c4; } +.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #1c94c4; text-decoration: none; } +.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #fbcb09; background: #fdf5ce url(../images/jquery-ui-theme/ui-bg_glass_100_fdf5ce_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #c77405; } +.ui-state-hover a, .ui-state-hover a:hover { color: #c77405; text-decoration: none; } +.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #fbd850; background: #ffffff url(../images/jquery-ui-theme/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #eb8f00; } +.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #eb8f00; text-decoration: none; } +.ui-widget :active { outline: none; } + +/* Interaction Cues +----------------------------------*/ +.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fed22f; background: #ffe45c url(../images/jquery-ui-theme/ui-bg_highlight-soft_75_ffe45c_1x100.png) 50% top repeat-x; color: #363636; } +.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; } +.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #b81900 url(../images/jquery-ui-theme/ui-bg_diagonals-thick_18_b81900_40x40.png) 50% 50% repeat; color: #ffffff; } +.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #ffffff; } +.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #ffffff; } +.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; } +.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } +.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { width: 16px; height: 16px; background-image: url(../images/jquery-ui-theme/ui-icons_222222_256x240.png); } +.ui-widget-content .ui-icon {background-image: url(../images/jquery-ui-theme/ui-icons_222222_256x240.png); } +.ui-widget-header .ui-icon {background-image: url(../images/jquery-ui-theme/ui-icons_ffffff_256x240.png); } +.ui-state-default .ui-icon { background-image: url(../images/jquery-ui-theme/ui-icons_ef8c08_256x240.png); } +.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(../images/jquery-ui-theme/ui-icons_ef8c08_256x240.png); } +.ui-state-active .ui-icon {background-image: url(../images/jquery-ui-theme/ui-icons_ef8c08_256x240.png); } +.ui-state-highlight .ui-icon {background-image: url(../images/jquery-ui-theme/ui-icons_228ef1_256x240.png); } +.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(../images/jquery-ui-theme/ui-icons_ffd27a_256x240.png); } + +/* positioning */ +.ui-icon-carat-1-n { background-position: 0 0; } +.ui-icon-carat-1-ne { background-position: -16px 0; } +.ui-icon-carat-1-e { background-position: -32px 0; } +.ui-icon-carat-1-se { background-position: -48px 0; } +.ui-icon-carat-1-s { background-position: -64px 0; } +.ui-icon-carat-1-sw { background-position: -80px 0; } +.ui-icon-carat-1-w { background-position: -96px 0; } +.ui-icon-carat-1-nw { background-position: -112px 0; } +.ui-icon-carat-2-n-s { background-position: -128px 0; } +.ui-icon-carat-2-e-w { background-position: -144px 0; } +.ui-icon-triangle-1-n { background-position: 0 -16px; } +.ui-icon-triangle-1-ne { background-position: -16px -16px; } +.ui-icon-triangle-1-e { background-position: -32px -16px; } +.ui-icon-triangle-1-se { background-position: -48px -16px; } +.ui-icon-triangle-1-s { background-position: -64px -16px; } +.ui-icon-triangle-1-sw { background-position: -80px -16px; } +.ui-icon-triangle-1-w { background-position: -96px -16px; } +.ui-icon-triangle-1-nw { background-position: -112px -16px; } +.ui-icon-triangle-2-n-s { background-position: -128px -16px; } +.ui-icon-triangle-2-e-w { background-position: -144px -16px; } +.ui-icon-arrow-1-n { background-position: 0 -32px; } +.ui-icon-arrow-1-ne { background-position: -16px -32px; } +.ui-icon-arrow-1-e { background-position: -32px -32px; } +.ui-icon-arrow-1-se { background-position: -48px -32px; } +.ui-icon-arrow-1-s { background-position: -64px -32px; } +.ui-icon-arrow-1-sw { background-position: -80px -32px; } +.ui-icon-arrow-1-w { background-position: -96px -32px; } +.ui-icon-arrow-1-nw { background-position: -112px -32px; } +.ui-icon-arrow-2-n-s { background-position: -128px -32px; } +.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } +.ui-icon-arrow-2-e-w { background-position: -160px -32px; } +.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } +.ui-icon-arrowstop-1-n { background-position: -192px -32px; } +.ui-icon-arrowstop-1-e { background-position: -208px -32px; } +.ui-icon-arrowstop-1-s { background-position: -224px -32px; } +.ui-icon-arrowstop-1-w { background-position: -240px -32px; } +.ui-icon-arrowthick-1-n { background-position: 0 -48px; } +.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } +.ui-icon-arrowthick-1-e { background-position: -32px -48px; } +.ui-icon-arrowthick-1-se { background-position: -48px -48px; } +.ui-icon-arrowthick-1-s { background-position: -64px -48px; } +.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } +.ui-icon-arrowthick-1-w { background-position: -96px -48px; } +.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } +.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } +.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } +.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } +.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } +.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } +.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } +.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } +.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } +.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } +.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } +.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } +.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } +.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } +.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } +.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } +.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } +.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } +.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } +.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } +.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } +.ui-icon-arrow-4 { background-position: 0 -80px; } +.ui-icon-arrow-4-diag { background-position: -16px -80px; } +.ui-icon-extlink { background-position: -32px -80px; } +.ui-icon-newwin { background-position: -48px -80px; } +.ui-icon-refresh { background-position: -64px -80px; } +.ui-icon-shuffle { background-position: -80px -80px; } +.ui-icon-transfer-e-w { background-position: -96px -80px; } +.ui-icon-transferthick-e-w { background-position: -112px -80px; } +.ui-icon-folder-collapsed { background-position: 0 -96px; } +.ui-icon-folder-open { background-position: -16px -96px; } +.ui-icon-document { background-position: -32px -96px; } +.ui-icon-document-b { background-position: -48px -96px; } +.ui-icon-note { background-position: -64px -96px; } +.ui-icon-mail-closed { background-position: -80px -96px; } +.ui-icon-mail-open { background-position: -96px -96px; } +.ui-icon-suitcase { background-position: -112px -96px; } +.ui-icon-comment { background-position: -128px -96px; } +.ui-icon-person { background-position: -144px -96px; } +.ui-icon-print { background-position: -160px -96px; } +.ui-icon-trash { background-position: -176px -96px; } +.ui-icon-locked { background-position: -192px -96px; } +.ui-icon-unlocked { background-position: -208px -96px; } +.ui-icon-bookmark { background-position: -224px -96px; } +.ui-icon-tag { background-position: -240px -96px; } +.ui-icon-home { background-position: 0 -112px; } +.ui-icon-flag { background-position: -16px -112px; } +.ui-icon-calendar { background-position: -32px -112px; } +.ui-icon-cart { background-position: -48px -112px; } +.ui-icon-pencil { background-position: -64px -112px; } +.ui-icon-clock { background-position: -80px -112px; } +.ui-icon-disk { background-position: -96px -112px; } +.ui-icon-calculator { background-position: -112px -112px; } +.ui-icon-zoomin { background-position: -128px -112px; } +.ui-icon-zoomout { background-position: -144px -112px; } +.ui-icon-search { background-position: -160px -112px; } +.ui-icon-wrench { background-position: -176px -112px; } +.ui-icon-gear { background-position: -192px -112px; } +.ui-icon-heart { background-position: -208px -112px; } +.ui-icon-star { background-position: -224px -112px; } +.ui-icon-link { background-position: -240px -112px; } +.ui-icon-cancel { background-position: 0 -128px; } +.ui-icon-plus { background-position: -16px -128px; } +.ui-icon-plusthick { background-position: -32px -128px; } +.ui-icon-minus { background-position: -48px -128px; } +.ui-icon-minusthick { background-position: -64px -128px; } +.ui-icon-close { background-position: -80px -128px; } +.ui-icon-closethick { background-position: -96px -128px; } +.ui-icon-key { background-position: -112px -128px; } +.ui-icon-lightbulb { background-position: -128px -128px; } +.ui-icon-scissors { background-position: -144px -128px; } +.ui-icon-clipboard { background-position: -160px -128px; } +.ui-icon-copy { background-position: -176px -128px; } +.ui-icon-contact { background-position: -192px -128px; } +.ui-icon-image { background-position: -208px -128px; } +.ui-icon-video { background-position: -224px -128px; } +.ui-icon-script { background-position: -240px -128px; } +.ui-icon-alert { background-position: 0 -144px; } +.ui-icon-info { background-position: -16px -144px; } +.ui-icon-notice { background-position: -32px -144px; } +.ui-icon-help { background-position: -48px -144px; } +.ui-icon-check { background-position: -64px -144px; } +.ui-icon-bullet { background-position: -80px -144px; } +.ui-icon-radio-off { background-position: -96px -144px; } +.ui-icon-radio-on { background-position: -112px -144px; } +.ui-icon-pin-w { background-position: -128px -144px; } +.ui-icon-pin-s { background-position: -144px -144px; } +.ui-icon-play { background-position: 0 -160px; } +.ui-icon-pause { background-position: -16px -160px; } +.ui-icon-seek-next { background-position: -32px -160px; } +.ui-icon-seek-prev { background-position: -48px -160px; } +.ui-icon-seek-end { background-position: -64px -160px; } +.ui-icon-seek-start { background-position: -80px -160px; } +/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ +.ui-icon-seek-first { background-position: -80px -160px; } +.ui-icon-stop { background-position: -96px -160px; } +.ui-icon-eject { background-position: -112px -160px; } +.ui-icon-volume-off { background-position: -128px -160px; } +.ui-icon-volume-on { background-position: -144px -160px; } +.ui-icon-power { background-position: 0 -176px; } +.ui-icon-signal-diag { background-position: -16px -176px; } +.ui-icon-signal { background-position: -32px -176px; } +.ui-icon-battery-0 { background-position: -48px -176px; } +.ui-icon-battery-1 { background-position: -64px -176px; } +.ui-icon-battery-2 { background-position: -80px -176px; } +.ui-icon-battery-3 { background-position: -96px -176px; } +.ui-icon-circle-plus { background-position: 0 -192px; } +.ui-icon-circle-minus { background-position: -16px -192px; } +.ui-icon-circle-close { background-position: -32px -192px; } +.ui-icon-circle-triangle-e { background-position: -48px -192px; } +.ui-icon-circle-triangle-s { background-position: -64px -192px; } +.ui-icon-circle-triangle-w { background-position: -80px -192px; } +.ui-icon-circle-triangle-n { background-position: -96px -192px; } +.ui-icon-circle-arrow-e { background-position: -112px -192px; } +.ui-icon-circle-arrow-s { background-position: -128px -192px; } +.ui-icon-circle-arrow-w { background-position: -144px -192px; } +.ui-icon-circle-arrow-n { background-position: -160px -192px; } +.ui-icon-circle-zoomin { background-position: -176px -192px; } +.ui-icon-circle-zoomout { background-position: -192px -192px; } +.ui-icon-circle-check { background-position: -208px -192px; } +.ui-icon-circlesmall-plus { background-position: 0 -208px; } +.ui-icon-circlesmall-minus { background-position: -16px -208px; } +.ui-icon-circlesmall-close { background-position: -32px -208px; } +.ui-icon-squaresmall-plus { background-position: -48px -208px; } +.ui-icon-squaresmall-minus { background-position: -64px -208px; } +.ui-icon-squaresmall-close { background-position: -80px -208px; } +.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } +.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } +.ui-icon-grip-solid-vertical { background-position: -32px -224px; } +.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } +.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } +.ui-icon-grip-diagonal-se { background-position: -80px -224px; } + + +/* Misc visuals +----------------------------------*/ + +/* Corner radius */ +.ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; } +.ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; } +.ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; } +.ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } +.ui-corner-top { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; } +.ui-corner-bottom { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } +.ui-corner-right { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } +.ui-corner-left { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; } +.ui-corner-all { -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; } + +/* Overlays */ +.ui-widget-overlay { background: #666666 url(../images/jquery-ui-theme/ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat; opacity: .50;filter:Alpha(Opacity=50); } +.ui-widget-shadow { margin: -5px 0 0 -5px; padding: 5px; background: #000000 url(../images/jquery-ui-theme/ui-bg_flat_10_000000_40x100.png) 50% 50% repeat-x; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }/* + * jQuery UI Resizable 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Resizable#theming + */ +.ui-resizable { position: relative;} +.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;} +.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } +.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; } +.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; } +.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; } +.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; } +.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } +.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } +.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } +.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/* + * jQuery UI Selectable 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Selectable#theming + */ +.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; } +/* + * jQuery UI Accordion 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Accordion#theming + */ +/* IE/Win - Fix animation bug - #4615 */ +.ui-accordion { width: 100%; } +.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; } +.ui-accordion .ui-accordion-li-fix { display: inline; } +.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; } +.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; } +.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; } +.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; } +.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; } +.ui-accordion .ui-accordion-content-active { display: block; } +/* + * jQuery UI Autocomplete 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Autocomplete#theming + */ +.ui-autocomplete { position: absolute; cursor: default; } + +/* workarounds */ +* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */ + +/* + * jQuery UI Menu 1.8.11 + * + * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Menu#theming + */ +.ui-menu { + list-style:none; + padding: 2px; + margin: 0; + display:block; + float: left; +} +.ui-menu .ui-menu { + margin-top: -3px; +} +.ui-menu .ui-menu-item { + margin:0; + padding: 0; + zoom: 1; + float: left; + clear: left; + width: 100%; +} +.ui-menu .ui-menu-item a { + text-decoration:none; + display:block; + padding:.2em .4em; + line-height:1.5; + zoom:1; +} +.ui-menu .ui-menu-item a.ui-state-hover, +.ui-menu .ui-menu-item a.ui-state-active { + font-weight: normal; + margin: -1px; +} +/* + * jQuery UI Button 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Button#theming + */ +.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */ +.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */ +button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */ +.ui-button-icons-only { width: 3.4em; } +button.ui-button-icons-only { width: 3.7em; } + +/*button text element */ +.ui-button .ui-button-text { display: block; line-height: 1.4; } +.ui-button-text-only .ui-button-text { padding: .4em 1em; } +.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; } +.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; } +.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; } +.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; } +/* no icon support for input elements, provide padding by default */ +input.ui-button { padding: .4em 1em; } + +/*button icon element(s) */ +.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; } +.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; } +.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; } +.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } +.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } + +/*button sets*/ +.ui-buttonset { margin-right: 7px; } +.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; } + +/* workarounds */ +button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */ +/* + * jQuery UI Dialog 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Dialog#theming + */ +.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; } +.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; } +.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; } +.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; } +.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; } +.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; } +.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; } +.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; } +.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; } +.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; } +.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } +.ui-draggable .ui-dialog-titlebar { cursor: move; } +/* + * jQuery UI Slider 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Slider#theming + */ +.ui-slider { position: relative; text-align: left; } +.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; } +.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; } + +.ui-slider-horizontal { height: .8em; } +.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; } +.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } +.ui-slider-horizontal .ui-slider-range-min { left: 0; } +.ui-slider-horizontal .ui-slider-range-max { right: 0; } + +.ui-slider-vertical { width: .8em; height: 100px; } +.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; } +.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } +.ui-slider-vertical .ui-slider-range-min { bottom: 0; } +.ui-slider-vertical .ui-slider-range-max { top: 0; }/* + * jQuery UI Tabs 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Tabs#theming + */ +.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ +.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; } +.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; } +.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; } +.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ +.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; } +.ui-tabs .ui-tabs-hide { display: none !important; } +/* + * jQuery UI Datepicker 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Datepicker#theming + */ +.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; } +.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } +.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } +.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } +.ui-datepicker .ui-datepicker-prev { left:2px; } +.ui-datepicker .ui-datepicker-next { right:2px; } +.ui-datepicker .ui-datepicker-prev-hover { left:1px; } +.ui-datepicker .ui-datepicker-next-hover { right:1px; } +.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } +.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } +.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; } +.ui-datepicker select.ui-datepicker-month-year {width: 100%;} +.ui-datepicker select.ui-datepicker-month, +.ui-datepicker select.ui-datepicker-year { width: 49%;} +.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } +.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } +.ui-datepicker td { border: 0; padding: 1px; } +.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } +.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } +.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } +.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } + +/* with multiple calendars */ +.ui-datepicker.ui-datepicker-multi { width:auto; } +.ui-datepicker-multi .ui-datepicker-group { float:left; } +.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } +.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } +.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } +.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } +.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } +.ui-datepicker-row-break { clear:both; width:100%; } + +/* RTL support */ +.ui-datepicker-rtl { direction: rtl; } +.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } +.ui-datepicker-rtl .ui-datepicker-group { float:right; } +.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } +.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } + +/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ +.ui-datepicker-cover { + display: none; /*sorry for IE5*/ + display/**/: block; /*sorry for IE5*/ + position: absolute; /*must have*/ + z-index: -1; /*must have*/ + filter: mask(); /*must have*/ + top: -4px; /*must have*/ + left: -4px; /*must have*/ + width: 200px; /*must have*/ + height: 200px; /*must have*/ +}/* + * jQuery UI Progressbar 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Progressbar#theming + */ +.ui-progressbar { height:2em; text-align: left; } +.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; } \ No newline at end of file diff --git a/public/stylesheets/messages.css b/public/stylesheets/messages.css new file mode 100644 index 0000000..086b8b6 --- /dev/null +++ b/public/stylesheets/messages.css @@ -0,0 +1,284 @@ + /* + * BID STATUS + */ +#bid-status { + background: url(../images/opacity/black-70.png); + padding: 10px; + font-family: Verdana, Geneva, Helvetica, Arial, sans-serif; + width: 290px; + position: fixed; + top: 15px; + right: 15px; + z-index: 9999; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + color: #fff; + display: none; +} +#bid-status p { + text-align: center; +} +#bid-status .success { + color: #0088CC; + margin-bottom: 5px; + font-weight: bold; +} +#bid-status .error { + color: #f22E2E; + margin-bottom: 5px; + font-weight: bold; +} + + + + + + + + + + + + +/* + * XHR RESPONSE + */ +#xhr-status { + background: #efe8c5; + border: 2px solid #d0c9a3; + font-size: 14px; + width: auto; + position: fixed; + left: 5px; + bottom: 5px; + z-index: 9999; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + padding: 0 10px; + display: none; +} +#xhr-status p { + width: auto; + text-align: center; + padding-bottom: 3px; +} +#xhr-status p.warning { + color: #ff0000; + font-weight: bold; + padding-top: 3px; +} + + + + + + + + + + + + +/* + * BUY NOW POPUP + */ +#buy-now-popup { + display: none; + font-size: 12px; + background: url(../images/opacity/black-80.png); + border: 2px solid #5d5d5d; + color: #fff; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + padding: 10px; + position: fixed; + width: 400px; + left: 50%; + margin-left: -200px; + top: 20%; + z-index: 9999; +} +#error-overlay { + display: none; + font-size: 12px; + background: #fff; + color: #fff; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + box-shadow: 0 0 7px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 0 7px rgba(0, 0, 0, 0.2); + -webkit-box-shadow: 0 0 7px rgba(0, 0, 0, 0.2); + border: 5px solid #C7C7C7; + padding: 10px 10px 30px 10px; + position: fixed; + width: 400px; + left: 50%; + margin-left: -200px; + top: 20%; + z-index: 9999; +} +#error-overlay .bid-unsuccessful { + margin-top: -10px; + height: 38px; + margin-bottom: 25px; + background: url(../images/msc/bid-unsuccessful.png) no-repeat; + font-size: 0; + text-indent: -9999px; +} +#error-overlay .explanation { + font-size: 1.2em; + line-height: 1.2em; + font-weight: bold; + color: #3B3B3B; + padding-left: 10px; +} +.overlay-popup-toggle { + float: right; + margin: -4px -4px 0 0; +} +.overlay-popup-toggle:hover { + cursor: pointer; +} +#buy-now-popup p.stop-message { + font-size: 1.2em; + font-weight: bold; + color: #70c7ed; + margin-bottom: 7px; +} +#buy-now-popup p.buy-now-price { + margin-bottom: 5px; +} +#buy-now-popup p.cheaper-than-hint { + color: #ef7a25; + margin-bottom: 13px; +} +#buy-now-popup p.button { + margin-bottom: 13px; +} +#buy-now-popup a.button { + width: 105px; + height: 30px; + background: url(../images/buttons/buy-now-popup.png); +} +#buy-now-popup p.explanation { + font-weight: bold; + margin-bottom: 3px; +} +#buy-now-popup table { + width: 50%; +} +#buy-now-popup table td.value { + text-align: right; +} +#buy-now-popup table tr.buy-now-price { + color: #70c7ed; + font-weight: bold; +} + + + + + + + + + + + + +/* + * FLASH MESSAGES + */ +.notice, .alert { + font-size: 0.9em; + background: #F3EBD7; + padding: 10px 0px; + font-family: Verdana, Geneva, Helvetica, Arial, sans-serif; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + color: #51b222; + margin: 0px auto 30px; + text-align: center; +} +.alert { + color: #f22E2E; +} +/* + * ERROR MESSAGES + */ +#errorExplanation { + font-size: 0.9em; + border: 2px solid #ef9aae; + color: #f22e2e; + padding: 15px; + margin-bottom: 35px; +} +#errorExplanation p { + margin: 0 0 7px 0; + color: #E50F42; +} +#errorExplanation ul li { + margin-left: 20px; + margin-bottom: 5px; + padding-left: 10px; + background: url(../images/msc/bullet.gif) no-repeat left 4px; + color: #808080; +} +.fieldWithErrors input { + background-color: #fee9fb; +} + + + + + + + + + +/* + * ORDER FAILURE + */ +#order-failure p { + margin-bottom: 13px; +} +#order-failure code { + font-size: 0.9em; + font-weight: bold; +} + + + + + + + + + + + + + + + + + + +/* FOR THOSE RUNNING ANCIENT COMPS */ +#unsupported-browser { + font-weight: bold; + border: 2px solid #c7c7c7; + padding: 5px; + font-size: 0.9em; + width: auto; + position: fixed; + top: 0; + left: 0; + z-index: 9999; + background: #F3EBD7; +} \ No newline at end of file diff --git a/public/stylesheets/orders.css b/public/stylesheets/orders.css new file mode 100644 index 0000000..9941cd6 --- /dev/null +++ b/public/stylesheets/orders.css @@ -0,0 +1,392 @@ +/* + * SHOPPING CART + */ +h2.my-shopping-cart { + background: url(../images/text/my-shopping-cart.gif); + margin-bottom: 35px; +} +h2.thank-you { + background: url(../images/text/thank-you.gif); +} +h2.were-sorry { + background: url(../images/text/were-sorry.gif); +} +#new-order .shopping-cart { + margin-bottom: 35px; +} +#new-order .shopping-cart th { + border-bottom: 2px solid #ccc; + line-height: 2.0em; + font-weight: bold; + text-align: center; +} +#new-order .shopping-cart td { + background: #eff2d7; + line-height: 2.5em; + text-align: center; +} +#new-order .shopping-cart .product { + padding-left: 1%; + text-align: left; +} +#new-order th.operator { + width: 3%; +} +#new-order th.product { + width: 40%; + text-align: left; +} +#new-order th.reg-price { + width: 11%; +} +#new-order th.shipping { + width: 11%; +} +#new-order th.member-discount { + width: 17%; +} +#new-order th.total { + +} + + + + + + + + + + + +/* + * NEW ORDERS + */ +/* ADDRESSES */ +.orders-page h2.shipping, .orders-page h2.billing, .orders-page h2.payment { + height: 20px; + background: url(../images/text/cart/shipping-address.gif); +} +.orders-page h2.billing { + background: url(../images/text/cart/billing-address.gif); +} +.orders-page h2.payment { + background: url(../images/text/cart/payment-options.gif); +} +#new-order h2.shipping { + margin-bottom: 25px; +} +#new-order { + min-height: 760px; + height: auto!important; +} +#checkout-address, #checkout-payments { + width: 400px; + height: auto!important; +} +#new-order .left-column-4 { + padding: 0; +} +/* LABELS */ +.orders-page .field label { + width: 120px; +} +#same-shipping-billing { + margin: 20px 0 0 130px; + width: 280px; +} +#same-shipping-billing input[type="checkbox"] { + margin: 5px 5px 10px 0; + float: left; +} +#same-shipping-billing label { + float: left; + width: 90%; + line-height: 1.2em; +} +#same-shipping-billing label:hover { + cursor: pointer; +} +#checkout-address .phone { + margin-bottom: 2px; +} +#checkout-address .phone-example { + margin-left: 130px; + font-size: 0.8em; + color: #808080; +} +/* BUTTON */ +.orders-page .action { + padding: 30px 0px 0px 130px; +} +#credit-card-form .button { + background: url(../images/buttons/continue.png); + height: 35px; + width: 130px; +} +/* PAYMENT TABS */ +.orders-page #payment-tabs { + margin-bottom: 15px; +} +.orders-page #payment-tabs ul { + height: 27px; + line-height: 27px; + background: url(../images/wrapper/payment-tabs/bg.png) repeat-x; +} +.orders-page #payment-tabs ul li { + float: left; + font-size: 0; + text-indent: -9999px; + height: 27px; +} +.orders-page #payment-tabs ul li:hover { + cursor: pointer; +} +.orders-page ul li#cc-tab { + background: url(../images/wrapper/payment-tabs/cc-bg.png) no-repeat; + width: 105px; + margin-left: 80px; +} +.orders-page ul li#pp-tab { + background: url(../images/wrapper/payment-tabs/pp-bg.png) no-repeat; + width: 74px; + margin-left: 5px; +} +.orders-page #payment-tabs ul li.selected { + background-position: 0 -27px; +} +/* PAYMENT FORMS */ +#paypal-form { + display: none; +} +#paypal-form img { + margin-bottom: 20px; +} +#paypal-form h3 { + font-size: 1.0em; + color: #2f2f2f; + font-weight: bold; + margin-bottom: 5px; +} +#paypal-form ul { + font-size: 0.9em; + margin-bottom: 15px; +} +#paypal-form ul li { + line-height: 1.2em; + margin-bottom: 10px; +} +#paypal-form p { + font-size: 0.9em; +} +#paypal-form .button { + background: url(../images/buttons/paypal.png); + height: 26px; + width: 146px; + outline-color: #808080; +} +.cvv input { + width: 60px; +} +.cc-type p { + display: inline-block; +} +/* SEPARATOR */ +#credit-card-form .separator { + height: 23px; + background: url(../images/msc/billing-separator.gif) no-repeat; +} +/* CART NUMBERS */ +#shopping-cart-numbers { + margin-bottom: 35px; + color: #3B3B3B; + font-size: 13px; + font-family: Helvetica Neue, Helvetica, Arial, sans-serif; +} +#shopping-cart-numbers table { + width: 300px; + margin-bottom: 7px; +} +#shopping-cart-numbers td { + line-height: 1.6em; +} +#shopping-cart-numbers td.label { + width: 65%; +} +#shopping-cart-numbers td.value { + width: 35%; + text-align: right; + padding-right: 10px; +} +#shopping-cart-numbers tr.member-discount td { + border-bottom: 1px solid #c7c7c7; + color: #EF7A25; +} +#shopping-cart-numbers tr.image td { + padding-bottom: 10px; +} +#shopping-cart-numbers tr.image p { + border: 5px solid #c7c7c7; + text-align: center; + width: 280px; +} +#shopping-cart-numbers tr.image img { +} +#shopping-cart-numbers tr.total td { + font-weight: bold; +} +#shopping-cart-numbers p { + font-size: 0.9em; +} + + + + + + +/* + * NEW ORDER + */ +#new-order #shipping-address { + display: none; +} + + + + + + +/* + * ORDER CONFIRMATION + */ +#confirm-order .left-column-1 { + padding: 0; +} +#confirm-order .right-column-1 { + padding: 0; + width: 42%; +} +#confirm-order h2.confirm-your-order { + background: url(../images/text/confirm-order.gif); +} +#confirm-order h3 { + margin-bottom: 5px; + padding-bottom: 3px; + border-bottom: 1px solid #c7c7c7; + width: 90%; +} +#confirm-order .wrapper { + margin-bottom: 35px; +} +#confirm-order .shopping-cart td { + line-height: 2.0em; + border-bottom: 1px dotted #ddd; +} +#confirm-order address, #confirm-order #credit-card table, #confirm-order #paypal p { + font-size: 0.9em; + padding-left: 15px; +} +/* CREDIT CARD */ +#confirm-order #credit-card, #confirm-order #paypal { + margin-bottom: 75px; +} +#confirm-ordertion #credit-card td { + line-height: 1.6em; +} +#confirm-order #credit-card td.label { + width: 30%; + text-align: right; +} +#confirm-order #credit-card td.value { + padding-left: 2%; + width: 68%; +} +#confirm-order #credit-card .cc-img { + width: 33px; + height: 21px; + float: left; + margin-right: 7px; +} +#confirm-order #credit-card p.card-number { + line-height: 21px; + height: 21px; +} +/* PLACE ORDER */ +#confirm-order #place-order p { + font-size: 0.85em; + margin-bottom: 10px; + width: 90%; + line-height: 1.2em; +} +#confirm-order .actions { + text-align: center; +} +#confirm-order .button { + width: 130px; + height: 35px; + background: url(../images/buttons/order-now.png); +} + + + + + + + + + +/* + * ORDER SUCCESS + */ +#order-success { + border: 5px solid #f7f7f7; + padding: 20px; +} +#order-success h3 { + color: #333; +} +#order-success h3, #order-success p { + margin-bottom: 15px; +} + + + + + + + +/* + * NEW BIDDER POPUP + */ +#new-bidder-popup { + position: fixed; + z-index: 9999; + top: 17%; + left: 50%; + margin-left: -300px; + width: 580px; + height: 365px; + padding: 75px 30px 20px 30px; + background: url(../images/wrapper/new-bidder-popup.png) no-repeat; +} +#new-bidder-popup .overlay-popup-toggle { + margin-top: -50px; +} +#new-bidder-popup p { + font-weight: bold; + margin-bottom: 13px; +} +#new-bidder-popup p.welcome { + font-size: 1.5em; + color: #EF7A25; +} +#new-bidder-popup a.button { + height: 45px; width: 140px; + background: url(../images/buttons/start-bidding.png); +} +#new-bidder-popup ul { + list-style: disc inside; +} +#new-bidder-popup ul li { + margin-bottom: 15px; +} diff --git a/public/stylesheets/product.css b/public/stylesheets/product.css new file mode 100644 index 0000000..fa4f17b --- /dev/null +++ b/public/stylesheets/product.css @@ -0,0 +1,1297 @@ +/* + * AUCTION INDEX & PRODUCT CONTAINERS --- USED ON REWARD/INDEX + */ +h2.ending-soon { + background: url(../images/text/ending-auctions.gif); +} +h2.upcoming-auctions { + background: url(../images/text/upcoming-auctions.gif); +} +td.auction-listing, td.product-listing { + width: 25%; + text-align: left; +} +.product-container .wrapper { + padding: 5px; +} +.product-container { + width: 220px; + height: 380px; + background: url(../images/wrapper/product-cell.png); + margin: 0 15px 30px -5px; + position: relative; + padding: 5px; +} +.auction-listing .beginner { + background: url(../images/wrapper/beginner-auction.png); +} +.auction-listing .featured { + background: url(../images/wrapper/featured-auction.png); +} +.auction-listing .hot { + background: url(../images/wrapper/hot-auction.png); +} +.auction-listing .auction-type-title-area { + width: 15px; + height: 83px; + position: absolute; + bottom: 15px; + left: 3px; +} +td.last .product-container { + margin-right: 0; +} +/* IMAGE */ +.product-container .image { + height: 204px; + overflow: hidden; +} +.product-container .image a { + display: block; + height: 204px; + text-align: center; +} +/* TITLE */ +.product-container .title { + width: 100%; + height: 50px; +} +.product-container .title h3 { + padding: 5px 5px 0 5px; + text-align: center; + font: 1em/1em "Helvetica Neue", Helvetica, Arial, sans-serif; + font-weight: bold; +} +.product-container .title p { + color: #808080; + font-size: 0.85em; + text-align: center; +} +/* TIMER */ +.product-container .timer-container { + font-size: 2.0em; + position: relative; +} +.product-container .timer-container .auction-timer { + text-align: center; +} +.product-container .timer-container .winner-text { + text-align: center; + display: none; + color: #ef7a25; +} +.product-container .timer-container .ended-text { + text-align: center; + display: none; +} +.timer-20 .timer-container .timer-reset-clock { + width: 22px; height: 22px; + background: url(../images/labels/timer-increment.gif) no-repeat 0 -40px; + position: absolute; + right: 25px; + top: 5px; + z-index: 10; +} +.auction-controls tr.timer p { + position: relative; + text-align: center; +} +.timer-30 .auction-controls tr.timer .timer-reset-clock, +.timer-20 .auction-controls tr.timer .timer-reset-clock { + width: 33px; height: 33px; + background: url(../images/labels/timer-increment.gif) no-repeat -30px 0; + position: absolute; + right: 25px; + top: 7px; + z-index: 10; +} +.timer-20 .auction-controls tr.timer .timer-reset-clock { + background-position: -30px -40px; +} +/* PRICE */ +.product-container .price-container { + text-align: center; + color: #4bc700; + font-size: 1.6em; + margin-bottom: 4px; +} +.product-container .auction-price { + padding: 0 7px; +} +/* LAST BIDDER */ +.product-container .last-bidder-container { + margin-bottom: 7px; + color: #808080; + text-align: center; + font-size: 0.9em; +} +.product-container .auction-last-bidder { + padding: 0 7px; +} +/* BUTTONS */ +.product-container .buttons .main, .product-container .buttons .buy-now { + width: 90px; height: 35px; + /* + float: left; + display: inline-block; + */ +} +.product-container .buttons .main { + /* + margin-left: 15px; + margin-right: 10px; + */ + margin: 0 auto; +} +.product-container .bid-button, .product-container .winner-button, .product-container .loser-button { + text-align: center; + width: 90px; +} +.auction-listing .buttons a, .auction-listing .buttons input { + width: 90px; + height: 35px; + background: url(../images/buttons/bid-small.gif); +} +/* INDEX BUY NOW */ +.product-container .buy-now a:hover { + text-decoration: none; +} +.product-container .buy-now p { + text-align: center; +} +.product-container .buy-now span { + display: block; + text-align: center; + background: url(../images/buttons/bid-small.gif) 0 -280px; + font-size: 0.9em; + padding-top: 3px; + width: 90px; height: 32px; + font-weight: bold; + color: #808080; +} +.product-container .buy-now span.buy-now-unavailable { + background: none; +} +.product-container .buy-now span.buy-now-unavailable p { + color: #3B3B3B; +} +.auction-listing .winner-button a { + background-position: 0 -160px; +} +.auction-listing .loser-button a { + background-position: 0 -200px; +} +.product-container .bid-button a.login:hover { + background-position: 0 -80px; +} +.product-container .bid-button a.registration:hover { + background-position: 0 -320px; +} +.auction .winner-button { + display: none; +} +.auction .loser-button { + display: none; +} +/* UPCOMING AUCTIONS */ +#upcoming-auctions { + padding-bottom: 55px; +} +#upcoming-auctions ul { + width: 180px; + float: left; + margin-right: 8px; +} +#upcoming-auctions ul li { + margin-bottom: 8px; +} +#upcoming-auctions ul li a { + color: #434343; + text-decoration: underline; +} +#upcoming-auctions ul li.title { + font-weight: bold; + font-size: 1.1em; +} + + + + + + + + + + + + + + + + + + +/* + * AUCTION/SHOW + */ +#auction-details .product-name { + margin-bottom: 30px; +} +#auction-details .product-name h2 { + margin-bottom: 0; + text-indent: 0; + height: 1em; +} +#auction-details td#add-to-watchlist { + width: 20%; +} +#auction-details td#add-to-watchlist a { + width: 20%; + width: 138px; + height: 23px; + background: url(../images/buttons/add-to-watchlist.png); + float: right; +} +/* + * GRID LAYOUT + */ +#auction-details #main-auction-grid { + float: left; + width: 630px; +} +#auction-details #main-auction-grid .block-first { + margin-bottom: 35px; +} +#auction-details #secondary-auction-grid { + float: right; + width: 300px; +} +#auction-details #secondary-auction-grid .wrapper { + float: right; + width: 290px; +} +#auction-details #secondary-auction-grid .block { + float: right; + padding: 10px; + width: 270px; + margin-bottom: 10px; + border: 1px solid #E0E0E0; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + -khtml-border-radius: 5px; + border-radius: 5px; +} +#auction-details #secondary-auction-grid .block h3 { + font-size: 1.1em; + padding-bottom: 0.5em; + margin-bottom: 0.8em; + color: #0088CC; + border-bottom: 1px solid #E0E0E0; +} +#auction-details #secondary-auction-grid .wrapper { + margin: 10px 0; +} +/* IMAGES --- SOME RULES ARE USED BY STORE/SHOW AS WELL */ +.product-images { + float: left; + min-height: 150px; + height: auto!important; + width: 290px; +} +.product-images #viewer { + width: 288px; + height: 260px; + border: 1px solid #e0e0e0; + -moz-border-radius: 5px 5px 0 0; + -webkit-border-radius: 5px 5px 0 0; + -khtml-border-radius: 5px 5px 0 0; + border-radius: 5px 5px 0 0; + text-align: center; +} +.product-images ul#gallery { + width: 288px; + border-bottom: 1px solid #e0e0e0; + border-left: 1px solid #e0e0e0; + border-right: 1px solid #e0e0e0; + -moz-border-radius: 0 0 5px 5px; + -webkit-border-radius: 0 0 5px 5px; + -khtml-border-radius: 0 0 5px 5px; + border-radius: 0 0 5px 5px; + padding: 9px 0; +} +.product-images ul#gallery li { + float: left; + width: 70px; + height: 65px; + padding: 0 1px; +} +.product-images ul#gallery li:hover { + cursor: pointer; +} +/* AUCTION CONTROLS */ +#auction-details .auction-controls, #auction-details .auction-ended { + width: 320px; + height: 345px; + float: right; +} +#auction-details .auction-ended { + display: none; +} +/* STATIC DETAILS PAGE DISPLAYS */ +#auction-details .history-page .auction-ended { + display: block; +} +#auction-details .history-page .winner-button { + display: block; +} +#auction-details .history-page .loser-button { + display: block; +} +table#main-numbers { + margin-bottom: 8px; +} +#main-numbers td.label { + width: 30%; + font-size: 11px; + color: #6d6d6d; +} +#main-numbers td.value { + width: 70%; +} +#main-numbers td.value p { + text-align: right; +} +/* PRICES */ +.auction-controls #main-numbers tr.price p { + margin-bottom: 5px; +} +.auction-controls #main-numbers tr.price .auction-price { + font-size: 2.5em; + color: #4bc700; +} +.auction-controls #main-numbers tr.price .shipping-price { + font-size: 11px; +} +/* BIDDER */ +.auction-controls tr.bidder td { + line-height: 3.0em; +} +.auction-controls span.auction-last-bidder { + padding: 0.3em 0 0.3em 0.3em; +} +/* FLASH TEXT */ +.auction-controls tr.flash { + text-align: center; +} +.auction-controls tr.flash .flash-text-wrapper { + height: 20px; + padding: 0.4em; +} +.auction-controls tr.flash .auction-flash-text { + text-align: center; + font-size: 0.9em; + font-weight: bold; +} +.auction-controls tr.flash div { + position: relative; +} +/* TIMER */ +.auction-controls tr.timer { + line-height: 4.0em; +} +.auction-controls tr.timer span.auction-timer { + font-size: 3.0em; + text-align: center; +} +/* BUTTONS */ +.auction-controls tr.auction-buttons td { + border-bottom: 1px solid #c7c7c7; +} +.auction-controls tr.auction-buttons .wrapper { + margin-bottom: 13px; +} +.auction-controls tr.auction-buttons .wrapper .button { + margin: 0 auto; + outline: 0 none; +} +.auction-controls tr.auction-buttons input[type="submit"], tr.auction-buttons a { + height: 40px; + width: 120px; + background: url(../images/buttons/bid-large.gif); +} +.auction-controls tr.auction-buttons a:hover { + background-position: 0 -100px; +} +/* RUNNING NUMBERS */ +table#current-numbers { + width: 165px; + line-height: 1.2em; + float: left; +} +#current-numbers td.label { + font-size: 11px; + color: #6D6D6D; +} +#current-numbers td.value { + text-align: right; +} +tr.bonuses-used td { + border-bottom: 1px solid #c7c7c7; +} +#percent-off { + float: left; + margin: 25px 0 0 20px; + font-size: 2.3em; + color: #808080; +} +/* BID HISTORY */ +#auction-bid-history { + height: 225px; +} +#bid-history th, #bid-history td { + font-size: 12px; + line-height: 1.70em; +} +#bid-history th { + border-bottom: 1px solid #c7c7c7; + font-weight: bold; + color: #6d6d6d; +} +#bid-history th.username { + width: 47%; +} +#bid-history th.price { + width: 20%; +} +#bid-history th.time { + width: 31%; + padding-left: 2%; +} +#bid-history td.time { + padding-left: 2%; + letter-spacing: -0.1px; +} +/* BID ASSISTANT */ +#bid-assistant h3 { + position: relative; +} +#bid-assistant .about-bid-assistant { + position: absolute; + display: inline-block; + width: 22px; + height: 23px; + background: url(../images/buttons/questionmark.gif); + top: -6px; + right: -3px; +} +#bid-assistant .clearfix { + margin-bottom: 15px; +} +#bid-assistant .controls { + float: left; +} +#bid-assistant .start-at { + margin-bottom: 10px; +} +/* BID ASSISTANT FORM ELEMENTS */ +#bid-assistant label { + display: inline-block; + width: 76px; + text-align: right; + color: #3B3B3B; + font-size: 0.9em; +} +#bid-assistant input[type="number"] { + text-align: right; + width: 60px; + padding: 2px; +} +#bid-assistant #bid_bot_submit { + margin: 15px 10px 0 0; + outline: 0 none; + width: 90px; + height: 30px; + background: url(../images/buttons/activate-bid-assistant.gif); + float: right; +} +#bid-assistant .edit_bid_bot #bid_bot_submit { + background-position: 0 -30px; +} +#bid-assistant .learn-more { + font-size: 0.9em; + color: #808080; +} +/* PRODUCT DESCRIPTION */ +#auction-details #product-description { + float: left; + width: 630px; +} +#auction-details #product-description h2 { + background: url(../images/text/product-description.gif) no-repeat; + margin-bottom: 1em; + padding-bottom: 0.2em; + border-bottom: 2px solid #f0f0f0; +} +/* PRODUCT DESCRIPTION TEXT FORMATTING */ +#product-description p, #product-description ul, #product-description ol { + margin-bottom: 15px; + line-height: 1.4em; +} +#product-description ul, #product-description ol { + margin-left: 25px; + list-style-position: inside; +} +#product-description ul { + list-style-type: disc; +} +/* BUY NOW */ +#buy-now p { + font-size: 0.9em; +} +/* BUY NOW IS AVAILABLE */ +#auction-details #buy-now .available p.description { + margin-bottom: 8px; +} +#auction-details #buy-now .available table { + float: left; + width: 70%; + line-height: 1.3em; + font-size: 0.9em; +} +#auction-details #buy-now .available td.value { + text-align: right; +} +#auction-details #buy-now .available tr.bonuses-used td { + padding-bottom: 2px; +} +#auction-details #buy-now .available tr.buy-now-price td { + padding-top: 2px; + color: #0088CC; + font-weight: bold; +} +#auction-details #buy-now .available p.button { + float: left; + margin: 4px 0 0 15px; +} +#auction-details #buy-now .available p.button a { + width: 60px; + height: 60px; + background: url(../images/buttons/buy-now-narrow.gif); +} +/* BUY NOW IS UNAVAILABLE */ +#buy-now .unavailable p { + font-size: 0.9em; +} +/* FB GUARANTEE */ +#auction-details .fb-guarantee img { + margin-bottom: 5px; +} +#auction-details #guarantee ul { + padding-left: 20px; +} +#auction-details #guarantee ul li { + line-height: 2.2em; + font-size: 13px; + color: #808080; + list-style: disc; +} +#auction-details #guarantee ul li.learn-more { + list-style: none; + padding-left: -20px; +} +/* ENDED AUCTIONS DETAILS */ +.auction-ended table.auction-numbers { + margin-bottom: 15px; +} +.auction-ended td.label { + width: 70%; +} +.auction-ended td.value { + width: 30%; + text-align: right; +} +.auction-ended tr.winner { + font-size: 1.5em; + font-weight: bold; + text-align: center; +} +.auction-ended tr.winner td { + padding-bottom: 10px; +} +.auction-ended tr.winner td p { + position: relative; +} +.auction-ended tr.price, .auction-ended tr.bonuses-used, .auction-ended tr.total-paid { + line-height: 1.3em; +} +.auction-ended tr.credits-used td { + padding: ; +} +.auction-ended tr.bonuses-used td { + padding-bottom: 2px; +} +tr.credits-used td { + font-weight: ; +} +.auction-ended tr.total-paid { + font-weight: bold; +} +.auction-ended tr.total-paid td { + padding-top: 2px; +} +.auction-ended tr.shipping { + font-size: 10px; +} +.auction-ended tr.shipping td { + padding-bottom: 17px; +} +.auction-ended tr.discount { + font-size: 1.95em; +} +.auction-ended tr.discount td { + padding-bottom: 5px; +} +.auction-ended tr.ended-text { + font-size: 2.0em; + color: #e50f42; +} +.auction-ended tr.time { + color: #e50f42; +} +.auction-ended .loser-button, .auction-ended .winner-button { + padding: 12px; +} +.auction-ended p { + text-align: center; +} +.auction-ended .button { + margin: 0 auto; + width: 120px; + height: 40px; +} +.auction-ended p.text { + margin-bottom: 12px; +} +.auction-eneded p.redeemed { + font-size: 0.9em; +} +.auction-ended .loser-button .button { + background: url(../images/buttons/bid-large.gif) 0 -250px; +} +.auction-ended .winner-button .text { + font-weight: bold; +} +.auction-ended .winner-button .button { + background: url(../images/buttons/bid-large.gif) 0 -200px; +} +/* SOCIAL MEDIA BUTTONS FOR AUCTION SHOW PAGE */ +#auction-details #social-media p, #auction-details #social-media ul li { + float: left; + height: 20px; + line-height: 20px; + font-size: 0.9em; + margin-bottom: 0px; +} +#auction-details #social-media ul li { + margin-left: 7px; +} +#auction-details #social-media ul li #tweet-button { + vertical-align: middle; +} +#auction-details #social-media ul li a { + display: block; +} +/* SHIPPING INFORMATIONAL FOOTER */ +#auction-details .shipping-information, #reward-store .shipping-information { + width: 910px; + border-radius: 7px; + -moz-border-radius: 7px; + -webkit-border-radius: 7px; + background: #f0f0f0; + padding: 15px; + line-height: 40px; + margin-top: 55px; +} +#auction-details .shipping-information .title, #reward-store .shipping-information .title { + float: left; + padding-right: 2.0em; + margin-right: 2.0em; + color: #0088CC; + text-transform: uppercase; + font-weight: bold; + border-right: 1px solid #c7c7c7; +} +#auction-details .shipping-information .delivery-cost, #auction-details .shipping-information .return-policy, +#reward-store .shipping-information .delivery-cost, #reward-store .shipping-information .return-policy { + float: left; + margin-right: 2.0em; +} +#auction-details .shipping-information .questions, #reward-store .shipping-information .questions { + float: left; +} + + + + + + + +/* + * AUCTION DETAILS REGISTRATION FORM + * + */ +#auction-details .ad-landing-page .auction-controls, #auction-details .ad-landing-page .auction-ended { + width: 298px; +} +#auction-details .ad-landing-page .auction-controls tr.timer span.auction-timer { + font-size: 2.5em; +} +#auction-details .ad-landing-page #percent-off { + margin: 25px 0 0 0; + float: right; + font-size: 2.0em; +} +#auction-details #registration-form { + margin: -10px -25px 10px -5px; + width: 300px; + float: right; + background: url(../images/promo/signup-short.png) no-repeat; + height: 310px; + padding: 60px 10px 10px 10px; +} +#auction-details #registration-form .input, #auction-details #registration-form .field { + margin-bottom: 9px; +} +#auction-details #registration-form .field label { + line-height: 24px; + font-size: 10px; + height: 24px; + width: 113px; + margin-right: 5px; + font-weight: bold; + color: #fff; +} +#auction-details #registration-form input[type="text"], #auction-details #registration-form input[type="password"] { + width: 170px; + line-height: 20px; + height: 20px; + padding: 0.2em; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; +} +#auction-details #registration-form select { + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; +} +/* USERNAME EXPLANATION */ +#auction-details #registration-form #username-explanation { + display: none; +} +/* D.O.B. */ +#auction-details #registration-form label.account-birth-date { + width: 100%; float: none; + padding-left: 35px; + text-align: left; + margin-top: -5px; +} +#auction-details #registration-form span.account-birth-date { + display: block; + padding-left: 55px; +} +#auction-details #registration-form select { + padding: 0.2em; +} +/* T.O.S */ +#auction-details #registration-form .checkbox-agreements { + font-size: 0.8em; + margin-left: 5px; + margin-bottom: 5px; +} +#auction-details #registration-form #tos-agreement { + margin-bottom: 5px; +} +#auction-details #registration-form .checkbox-agreements input { + float: left; + margin-top: 2px; +} +#auction-details #registration-form .checkbox-agreements p { + padding-left: 17px; + color: #fff; +} +#auction-details #registration-form .checkbox-agreements a { + color: #fff; + font-weight: bold; +} +/* REGISTER BUTTON */ +#auction-details #registration-form .actions input { + margin-left: 120px; + height: 30px; + width: 80px; + background: url(../images/buttons/submit.png) no-repeat; +} + + + + + + + + + +/* + * AUCTION HISTORY + */ +h2.past-auction-winners { + background: url(../images/text/past-auction-winners.gif); +} +#auctions-history .auctions-ended { + margin-bottom: 10px; +} +#auctions-history .pagination { + margin-bottom: 55px; +} +/* COLUMN WIDTHS -- USED BY BOTH TITLE AND LISTING TABLE */ +#auctions-history td.image { + width: 120px; +} +#auctions-history td.product { + width: 265px; +} +#auctions-history td.ended { + width: 220px; +} +#auctions-history td.price { + +} +/* TITLE TABLE */ +#auctions-history tr.title { + background: #f7f7f7; + -moz-border-radius: 3px; +} +#auctions-history tr.title td { + padding: 3px; + text-align: center; + font-weight: bold; + color: #808080; +} +/* LISTING TABLE */ +#auctions-history .auction-listing td { + padding: 10px 3px; + height: 110px; + text-align: center; + border-bottom: 3px solid #f7f7f7; +} +#auctions-history .auction-listing td.image a { + height: 110px; + display: block; + outline: 0 none; + text-align: center; +} +#auctions-history td.ended span.ended-text { + font-size: 1.65em; + color: #E50F42; +} +#auctions-history td.ended span.winner { + display: block; + text-align: center; + padding-top: 5px; + font-weight: bold; + color: #808080; +} +#auctions-history .auction-listing td.price .alignC { + position: relative; +} +#auctions-history .auction-listing td.price span.auction-price { + font-size: 1.65em; +} +#auctions-history .auction-listing td.savings { + color: #0088CC; + font-size: 1.8em; +} +/* GET STARTED */ +#auctions-history #get-started { + padding: 15px; + background: #f7f7f7; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + border-radius: 5px; +} +#auctions-history #get-started h2 { + margin-bottom: 15px; +} +#auctions-history #get-started p { + line-height: 1.3em; + margin-bottom: 10px; +} + + + + + + + + + + +/* + * INCREMENTS + */ +/* PRICE - INDEX */ +#auctions-index .bid-increment { + width: 50px; height: 20px; + display: block; + position: absolute; + top: 55px; left: 2px; + z-index: 10; + background: url(../images/labels/index-price-increment.png) no-repeat; +} +#auctions-index .price-5 .bid-increment { + background-position: 0 -25px; +} +#auctions-index .price-15 .bid-increment { + background-position: 0 -50px; +} +/* PRICE - NONINDEX */ +#auction-details .bid-increment, #auctions-history .bid-increment { + width: 36px; height: 36px; + display: block; + position: absolute; + top: 0; left: 0; + z-index: 10; + background: url(../images/labels/price-increment.png); +} +#auction-details .price-5 .bid-increment, #auctions-history .price-5 .bid-increment { + background-position: 0 -40px; +} +#auction-details .price-15 .bid-increment, #auctions-history .price-15 .bid-increment { + background-position: 0 -80px; +} + + + + + + + + + + + +/* + * SOLD OVERLAY + */ +#auctions-index .ended-trigger .sold-overlay { + width: 220px; + height: 204px; + display: block; + position: absolute; + top: 55px; + left: 5px; + z-index: 5; + background: url(../images/labels/sold-overlay.png) center center no-repeat; +} +#auctions-index .sold-overlay a { + text-indent: -9999px; + font-size: 0; + line-height: 0; + display: none; +} +#auctions-index .ended-trigger .sold-overlay a { + display: block; + height: 204px; + width: 220px; + outline: 0 none; +} + + + + + + + + +/* + * STORE INDEX --- .product-container IS USED TO STYLE BOTH MEMBER STORE AND AUCTION INDEX + */ +h2.members-shop { + background: url(../images/text/members-shop.gif); +} +#store-explanation { + margin-bottom: 25px; +} +#store-explanation p { + font-size: 1.1em; + line-height: 1.2em; +} +/* + * DISCOUNT NUMBERS --- #reward-store .discount-numbers REULES ARE REQUIRED FOR STORE/SHOW + */ +.product-listing .image { + margin-bottom: 5px; +} +#reward-store .discount-numbers { + width: 92%; + margin: 0px auto; + font-size: 11.5px; +} +#reward-store .discount-numbers td.action { + width: 4%; + padding-right: 2px; +} +#reward-store .discount-numbers td.label { + width: 40%; +} +#reward-store .discount-numbers td.value { + text-align: right; +} +#reward-store tr.member-points td { + border-bottom: 2px solid #c7c7c7; + padding-bottom: 3px; +} +#reward-store tr.member-price td { + padding-top: 3px; +} +#reward-store tr.member-price span { + color: #000; + font-weight: bold; +} +#reward-store tr.member-price span.price { + color: #0088CC; +} +#reward-store tr.shipping-price td { + text-align: right; + font-style: italic; +} +#reward-store .redeem { + text-align: center; + padding: 15px; +} +#reward-store .redeem a { + width: 165px; + height: 35px; + background: url(../images/buttons/redeem-points.png); + margin: 0px auto; +} +/* + * STORE/SHOW + */ +#reward-store #main-store-grid { + width: 630px; + float: left; +} +#reward-store #secondary-store-grid { + width: 300px; + float: right; +} +#reward-store #product-name { + text-indent: 0; +} +#reward-store .product-images { + float: right; + margin-bottom: 10px; +} +/* DISCOUNT BOX */ +#reward-store .discount-container { + float: right; + padding: 10px; + width: 270px; + margin-bottom: 10px; + border: 1px solid #E0E0E0; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + -khtml-border-radius: 5px; + border-radius: 5px; +} +#reward-store .discount-container h3 { + font-size: 1.1em; + padding-bottom: 0.5em; + margin-bottom: 0.8em; + color: #0088CC; + border-bottom: 1px solid #E0E0E0; +} +#reward-store .discount-container .redeem { + padding-bottom: 0; +} + + + + + + + + + + + + + +/* + * WELCOME SPLASH + */ +.penny-promo #new-bids-order { + margin-bottom: 35px; +} +#welcome-page h2.almost-ready { + height: 40px!important; + background: url(../images/promo/welcome-heading.jpg) no-repeat; +} +#welcome-page #welcome-splash { + height: 378px; + background: url(../images/promo/welcome-splash.jpg) no-repeat; + margin-bottom: 20px; +} +#welcome-page #winners-table { + height: 600px; + background: url(../images/promo/winners-table.jpg) no-repeat; + margin-bottom: 35px; +} +#welcome-page #buy-bids-explanation { + border: 1px dashed #c7c7c7; + padding: 20px; + line-height: 27px; + font-size: 1.3em; + margin-bottom: 35px; + color: #808080; + border-radius: 7px; + -moz-border-radius: 7px; + -webkit-border-radius: 7px; +} +#welcome-page #buy-bids-explanation img { + margin-bottom: -5px; +} + + + + + + + + + + + +/* + * BUY BIDS PAGES + */ +h2.buy-bids { + background: url(../images/text/buy-bids.gif); +} +#new-bids-order .left-column-4 .wrapper { + width: 410px; + color: #5B5B5B; +} +#new-bids-order .left-column-4 .wrapper h3 { + background: #434343; + color: #fff; + font-size: 13px; + padding: 7px; + font-weight: bold; +} +#new-bids-order .left-column-4 #satisfaction-guarantee { + font-size: 0; + text-indent: -9999px; + width: 410px; + height: 100px; + background: url(../images/msc/satisfaction-guarantee.png) no-repeat; + margin-bottom: 25px; +} +.bid-pack { + height: 40px; + line-height: 40px; + padding-left: 10px; + border-bottom: 1px solid #c7c7c7; + width: 400px; + display: block; +} +.recommended-bid-pack { + background: url(../images/bidpacks/recommended-bid-pack.jpg) no-repeat; +} +.bid-pack input { + float: left; + margin: 13px 13px 13px 0; +} +.bid-pack label { + float: left; + display: block; + height: 40px; + width: 365px; +} +.bid-pack label:hover { + cursor: pointer; +} +.bid-pack label .size { + width: 40%; + display: -moz-inline-stack; + display: inline-block; + zoom: 1; + *display: inline; + _height: 40px; +} +.bid-pack label .price { + width: 50%; + text-align: right; + display: -moz-inline-stack; + display: inline-block; + zoom: 1; + *display: inline; + _height: 40px; +} +#bid-pack-submit { + margin: 35px 85px; +} +#bid-pack-submit input { + background: url(../images/buttons/checkout.png); + width: 130px; + height: 35px; +} + + + + + + + + + + + +/* + * BEGINNER AUCTION POPUP + */ +#beginner-auction-popup { + position: fixed; + z-index: 9999; + top: 15%; + left: 50%; + margin-left: -223px; + width: 386px; + height: 219px; + padding: 75px 30px 30px 30px; + background: url(../images/wrapper/beginner-auction-popup.png) no-repeat; +} +#beginner-auction-popup .overlay-popup-toggle { + margin-top: -50px; +} +#beginner-auction-popup .block { + margin-bottom: 13px; +} +#beginner-auction-popup p.welcome { + font-size: 1.2em; + font-weight: bold; + color: #EF7A25; + text-transform: uppercase; +} +#beginner-auction-popup p.question { + background: url(../images/msc/bullet.gif) no-repeat left 4px; + padding-left: 10px; + font-weight: bold; + margin-bottom: 3px; +} +#beginner-auction-popup p.answer { + padding-left: 10px; +} +#beginner-auction-popup .signature p { + margin-bottom: 5px; +} diff --git a/public/stylesheets/tiptip.css b/public/stylesheets/tiptip.css new file mode 100644 index 0000000..f1af53b --- /dev/null +++ b/public/stylesheets/tiptip.css @@ -0,0 +1,120 @@ +/* TipTip CSS - Version 1.2 */ + +.hasTooltip { + cursor: pointer; +} + +#tiptip_holder { + display: none; + position: absolute; + top: 0; + left: 0; + z-index: 99999; +} + +#tiptip_holder.tip_top { + padding-bottom: 5px; +} + +#tiptip_holder.tip_bottom { + padding-top: 5px; +} + +#tiptip_holder.tip_right { + padding-left: 5px; +} + +#tiptip_holder.tip_left { + padding-right: 5px; +} + +#tiptip_content { + font-size: 12px; + color: #ebebeb; + padding: 6px 10px; + border: 1px solid rgba(255,255,255,0.25); + background: rgb(25,25,25); + background: rgba(25,25,25,0.92); + background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(transparent), to(#000)); + border-radius: 3px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + /* + box-shadow: 0 0 1px #555; + -webkit-box-shadow: 0 0 3px #555; + -moz-box-shadow: 0 0 3px #555; + */ +} +#tiptip_content br { + margin-bottom: 5px; +} +#tiptip_arrow, #tiptip_arrow_inner { + position: absolute; + border-color: transparent; + border-style: solid; + border-width: 6px; + height: 0; + width: 0; +} + +#tiptip_holder.tip_top #tiptip_arrow { + border-top-color: #fff; + border-top-color: rgba(255,255,255,0.35); +} + +#tiptip_holder.tip_bottom #tiptip_arrow { + border-bottom-color: #fff; + border-bottom-color: rgba(255,255,255,0.35); +} + +#tiptip_holder.tip_right #tiptip_arrow { + border-right-color: #fff; + border-right-color: rgba(255,255,255,0.35); +} + +#tiptip_holder.tip_left #tiptip_arrow { + border-left-color: #fff; + border-left-color: rgba(255,255,255,0.35); +} + +#tiptip_holder.tip_top #tiptip_arrow_inner { + margin-top: -7px; + margin-left: -6px; + border-top-color: rgb(25,25,25); + border-top-color: rgba(25,25,25,0.92); +} + +#tiptip_holder.tip_bottom #tiptip_arrow_inner { + margin-top: -5px; + margin-left: -6px; + border-bottom-color: rgb(25,25,25); + border-bottom-color: rgba(25,25,25,0.92); +} + +#tiptip_holder.tip_right #tiptip_arrow_inner { + margin-top: -6px; + margin-left: -5px; + border-right-color: rgb(25,25,25); + border-right-color: rgba(25,25,25,0.92); +} + +#tiptip_holder.tip_left #tiptip_arrow_inner { + margin-top: -6px; + margin-left: -7px; + border-left-color: rgb(25,25,25); + border-left-color: rgba(25,25,25,0.92); +} + +/* Webkit Hacks */ +@media screen and (-webkit-min-device-pixel-ratio:0) { + #tiptip_content { + padding: 4px 8px 5px 8px; + background-color: rgba(45,45,45,0.88); + } + #tiptip_holder.tip_bottom #tiptip_arrow_inner { + border-bottom-color: rgba(45,45,45,0.88); + } + #tiptip_holder.tip_top #tiptip_arrow_inner { + border-top-color: rgba(20,20,20,0.92); + } +} \ No newline at end of file diff --git a/public/stylesheets/viewer.css b/public/stylesheets/viewer.css new file mode 100644 index 0000000..8f4a7cd --- /dev/null +++ b/public/stylesheets/viewer.css @@ -0,0 +1,358 @@ +/* +Copyright 2010 Expedient Shopping, Inc. +Not to be copied or distributed without the written consent of Expedient Shopping, Inc. +*/ + +html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, h7, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, del, dfn, font, img, ins, kbd, q, s, samp, +sub, sup, tt, var, dd, dl, dt, li, ol, ul, form, fieldset, input, textarea, label, +table, legend, caption, tbody, tfoot, thead, tr, th, td{ + font-family:inherit; + font-weight:inherit; + font-style:inherit; + font-size:100%; + text-align:left; + margin:0; + padding:0; +} +.clearfix:after { + content: " "; + display: block; + height: 0; + clear: both; + visibility: hidden; +} +.clearfix { + display: inline-block; +} +.clearfix_inline:after { + content: " "; + display: block; + height: 0; + clear: both; + visibility: hidden; +} +.clearfix_inline { + width: 100%; +} +html, body { + height: 100%; + width: 100%; + max-height: 100%; +} +html { + font-family: Helvetica, Arial, sans-serif; + font-size: 12px; + color: #d0d0d0; +} +body { + min-width: 700px; + min-height: 600px; +} +#container { + display: block; + height: 100%; + width: 100%; + position: relative; + z-index: 5; +} +h1 { + position: absolute; + right: 0; + top: 0; + z-index: 10; +} +#content-wrapper { + top: 50%; + margin-top: -255px; + left: 9%; + z-index: 10; + overflow: hidden; + width: 425px; + position: absolute; + padding: 30px 50px; + background: url(../images/viewer/20_opacity_black.png); + height: 410px; +} +#content { + padding: 20px; + border: 1px solid #1a1a1a; + background: url(../images/viewer/75_opacity_black.png); + height: 358px; +} +#background { + height: 100%; + width: 100%; + position: absolute; + overflow: hidden; + z-index: -10; +} +#background img { + left: 0; + position: absolute; + top: 0; + z-index: -10; + width: 100%; +} +#footer { + position: fixed; + bottom: 0; + width: 100%; + z-index: 9999; +} +/*Opera Fix*/ +body:before { + content:""; + height:100%; + float:left; + width:0; + margin-top:-32767px; +} +img { + border: 0 none; +} +ul { + list-style: none; +} +table { + width: auto; +} +input[type="submit"] , button { + border: 0 none; + color: #fff; + font-weight: bold; + text-align: center; + background-color: #000; +} +input[type="submit"]:hover , button:hover { + cursor: pointer; +} +fieldset { + border: 0 none; +} + + + + + + + +/*------------------------------- Typography -------------------------------*/ +a { + text-decoration: none; + color: #f3dc8c; +} +a:hover { + text-decoration: underline; +} +h1 { + text-align: right; + padding: 10px; +} +h1 a { + color: #fff; +} +h2 { + font-size: 1.25em; + color: #ebd55b; + margin-bottom: 20px; +} +h3 { + color: #EBD55B; + font-size: 1.2em; + margin-bottom: 8px; +} +p { + margin-bottom: 10px; + font-size: 1.1em; +} +.error, .success { + color: #ff6333; + padding:5px; + border: 1px solid #363231; + margin-bottom: 12px; + height: 18px; + margin-top: -42px; + text-align: center; + font-size: 1.0em; +} +.success { + color: #9dc075; +} + + + + + + + + +/*------------------------------- FORMS -------------------------------*/ +label { + display: block; + float: left; + width: 70px; + text-align: right; + margin-right: 10px; + line-height: 26px; + text-transform: capitalize; +} +input[type="text"], input[type="password"] { + float: left; + padding: 0.5em; + width: 225px; + border: 0 none; + background: url(../images/viewer/8_opacity_white.png); + color: #fff; + margin-right: 3px; +} +input[type="submit"] { + width: 82px; + height: 28px; + background: url(../images/viewer/submit_btn.png) no-repeat scroll 0 0; + font-size: 0.9em; + color: #c3b98d; +} +input[type="submit"]:hover { + background: url(../images/viewer/submit_btn.png) no-repeat scroll 0 -28px; + color: #EBD55B; +} +form .field { + margin-bottom: 10px; +} +form .actions { + margin-left: 80px; + margin-bottom: 5px; +} +#signin .authorized { + margin-bottom: 10px; + color: #EBD55B; +} +#signin .message { + margin-left: 80px; + font-size: 0.9em; + color: #c7c7c7; +} +#signin #contact-link { + color: #F3DC8C; +} +#signin #contact-link:hover { + text-decoration: underline; + cursor: pointer; +} + + + + + + + + + +/*------------------------------- Contacts -------------------------------*/ +#contact-page #content-wrapper { + font-size: 1.1em; +} +#contact-page #content, #about-page #content { + display: block; +} +#contacts { + width: 80px; + padding-right: 30px; + float: left; + height: 100%; +} +#contacts li { + text-align: right; + line-height: 35px; + font-weight: bold; +} +#contacts-info { + padding-left: 40px; + float: left; + border-left: 1px solid #5b5b5b; + height: 100%; +} +#contacts-info a { + line-height: 35px; +} +#contacts-info address { + padding-top: 25px; +} +#about-page { + display: none; +} +#contact-page { + display: none; +} + + + + + + + + + + + +/*------------------------------- Footer -------------------------------*/ +#footer { + height: 25px; + padding-top: 1px; + clear: both; + margin-top: -26px; + background: url(../images/viewer/footer_bg.png) repeat-x scroll 0 0; +} +#footer ul li { + float: right; +} +#footer ul li span { + width: 100px; + text-align: center; + color: #fff; +/* text-shadow: -1px -1px #5a5a5a; */ + text-decoration: none; + line-height: 25px; + font-family: Lucida Sans Unicode, Lucida Grande; + text-transform: uppercase; + font-size: 0.9em; + display: block; + border-left: 1px solid #4a4a4a; +} +#footer ul li span:hover { + background: url(../images/viewer/50_opacity_black.png); + cursor: pointer; +} +#footer ul li span.selected { + background: url(../images/viewer/75_opacity_black.png); +} +#image-loader { + display: none; +} + + + + + + + + + + + + +/*------------------------------- Footer -------------------------------*/ +#errorExplanation { + height: 60px; +} +#errorExplanation p { + margin: 0 0 5px 0; + color: #c5259d; +} +#errorExplanation ul li { + margin-left: 20px; + margin-bottom: 5px; + padding-left: 10px; + background: url(../images/msc/bullet.gif) no-repeat left 4px; +} diff --git a/public/watchdog-recovery.html b/public/watchdog-recovery.html new file mode 100644 index 0000000..7fc5124 --- /dev/null +++ b/public/watchdog-recovery.html @@ -0,0 +1,87 @@ + + + + FirstBargain technical difficulties. System recovering... + + + + + + +
    + +

    We are experiencing technical difficulties.

    +

    Auctions scheduled to end within the past minute have been restarted with 10 minutes added to their timers.

    +

    Automatic system recovery ready in: 30 seconds.

    +

    You will be redirected once recovery is ready.

    +
    + + diff --git a/public/widget.html b/public/widget.html new file mode 100644 index 0000000..66d6b4f --- /dev/null +++ b/public/widget.html @@ -0,0 +1,15 @@ + + + + Widget demo + + + + + +
    + + \ No newline at end of file diff --git a/script/rails b/script/rails new file mode 100755 index 0000000..f8da2cf --- /dev/null +++ b/script/rails @@ -0,0 +1,6 @@ +#!/usr/bin/env ruby +# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. + +APP_PATH = File.expand_path('../../config/application', __FILE__) +require File.expand_path('../../config/boot', __FILE__) +require 'rails/commands' diff --git a/test/factories.rb b/test/factories.rb new file mode 100644 index 0000000..d51ee92 --- /dev/null +++ b/test/factories.rb @@ -0,0 +1,104 @@ +# encoding: utf-8 + +# Accounts + +Factory.define :account do |f| + f.sequence(:username) { |n| "foo#{n}" } + f.sequence(:email) { |n| "foo#{n}@example.com" } + f.birth_date {20.years.ago} + f.password 'foobar' + f.password_confirmation {|u| u.password} + f.sequence(:registration_ip) { |n| "127.0.0.#{n}"} + f.current_login_ip {|u| u.registration_ip} + f.last_login_ip {|u| u.registration_ip} + f.skip_session_maintenance true +end + +# Auctions + +Factory.define :auction do |f| + f.association :product + f.ending_at {1.hour.from_now} + f.retail_price Money.new(1995) +end + +Factory.define :featured_auction do |f| + f.association :auction + f.name "Hey! Buy This!" + f.description "This item is really great. You should bid on it." + f.image_url {|fa| fa.auction.product.main_picture.url :medium} +end + +# Product + +Factory.define :product do |f| + f.sequence(:name) {|n| "Lowe's $25 Gift Card #{n}"} + f.summary "Lowe's $25 Gift Card" + f.description "The Lowe’s Gift Card is the perfect gift for everything home with the choice of over 50,000 items. Building supplies, tools, appliances, home improvement services, do it yourself help and hundreds of ideas to decorate and personalize your home. From rooftops to basements, ceilings to floors, indoors to out, you can find it all at Lowe’s." + f.retail_price Money.new(2500) + f.main_picture File.open("#{Rails.root}/test/fixtures/products/lowes-gift-card.jpg") + f.tax 0.to_money + f.cost {|p| p.retail_price} + f.association :category +end + +# Categories + +Factory.define :category do |f| + f.name "Gift Cards" +end + +# Orders + +Factory.define :order do |f| + f.association :account + f.ip_address "127.0.0.1" + f.first_name "Caleb" + f.last_name "Perkins" + #f.card_type "mastercard" + #f.card_number "4111111111111111" + #f.card_verification "123" + #f.card_expires_on 1.year.from_now + f.billing_address "1615 SW 158 Avenue" + f.billing_address_2 "" + f.billing_city "Pembroke Pines" + f.billing_state "Florida" + f.billing_zip "33027" + f.billing_phone "607-351-4028" + f.shipping_name {|o| o.billing_name} + f.shipping_address {|o| o.billing_address} + f.shipping_address_2 {|o| o.billing_address_2} + f.shipping_city {|o| o.billing_city} + f.shipping_state {|o| o.billing_state} + f.shipping_zip {|o| o.billing_zip} + f.shipping_phone {|o| o.billing_phone} +end + +Factory.define :bid_order, :parent => :order, :class => BidOrder do |f| + f.quantity 50 +end + +Factory.define :auction_order, :parent => :order, :class => AuctionOrder do |f| + f.association :auction +end + +# Contacts + +Factory.define :contact do |f| + f.email "caleb@example.com" + f.subject "A simple test" + f.message "Hope this works!" +end + +Factory.define :investment do |f| +end + +Factory.define :bid do |f| +end + +Factory.define :bid_bot do |f| + f.association :account + f.association :auction + f.bid_from 0.to_money + f.bids_left 3 +end \ No newline at end of file diff --git a/test/fixtures/products/lowes-gift-card.jpg b/test/fixtures/products/lowes-gift-card.jpg new file mode 100644 index 0000000..43b2c1d Binary files /dev/null and b/test/fixtures/products/lowes-gift-card.jpg differ diff --git a/test/functional/accounts_controller_test.rb b/test/functional/accounts_controller_test.rb new file mode 100644 index 0000000..c715ab6 --- /dev/null +++ b/test/functional/accounts_controller_test.rb @@ -0,0 +1,44 @@ +require 'test_helper' + +class AccountsControllerTest < ActionController::TestCase + setup :activate_authlogic + + test "register page with referral cookies" do + assert_logged_out + get :new, :u => "lunatic" + assert_response :success, @response.body + assert_equal "lunatic", cookies["referral"] + end + + test "registering with bad info" do + post :create, :account => {:username => ""} + assert_response :success, @response.body + assert_template :create + end + + test "registering with good info" do + post :create, :account => Factory.attributes_for(:account) + assert_equal nil, cookies[:referral] + assert_equal true, session[:welcome] + assert_redirected_to welcome_account_url + end + + test "account screen" do + u = Factory :account + AccountSession.create u + get :show + assert_response :success, @response.body + assert_not_nil assigns(:winnings) + assert_not_nil assigns(:wins) + assert_not_nil assigns(:buynows) + end + + test "account settings" do + u = Factory :account + AccountSession.create u + get :edit + assert_response :success, @response.body + assert_template :edit + end + +end diff --git a/test/functional/activations_controller_test.rb b/test/functional/activations_controller_test.rb new file mode 100644 index 0000000..3e9f331 --- /dev/null +++ b/test/functional/activations_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class ActivationsControllerTest < ActionController::TestCase + setup :activate_authlogic + + test "nonexistant accounts get redirected" do + get :new + assert_response :redirect + assert_equal I18n.t("flash.activations.account_not_found"), flash.alert + get :new, {:code => "invalid"} + assert_response :redirect + assert_equal I18n.t("flash.activations.account_not_found"), flash.alert + end + + test "already verified accounts get redirected" do + a = Factory :account + a.activate + get :new, {:code => a.single_access_token} + assert_response :redirect + assert_equal I18n.t("flash.activations.already_verified"), flash.alert + end + + test "found account gets activated" do + a = Factory :account + assert !a.verified?, "new accounts shouldn't be already verified" + get :new, {:code => a.single_access_token} + assert_response :redirect + assert a.reload.verified?, "should have been verified" + assert_equal I18n.t("flash.activations.activated"), flash.notice + end + + test "can't request activation if verified" do + a = Factory :account + a.activate + AccountSession.create a + post :create + assert_response :redirect, @response.body + assert_equal I18n.t("flash.activations.already_verified"), flash.alert + end + + test "can request activation" do + a = Factory :account + AccountSession.create a + post :create + assert_response :redirect, @response.body + assert_equal I18n.t("flash.activations.created"), flash.notice + end + +end diff --git a/test/functional/admin/orders_controller_test.rb b/test/functional/admin/orders_controller_test.rb new file mode 100644 index 0000000..10bdff9 --- /dev/null +++ b/test/functional/admin/orders_controller_test.rb @@ -0,0 +1,17 @@ +require 'test_helper' + +class Admin::OrdersControllerTest < ActionController::TestCase + setup :activate_authlogic + + def setup + @b = Factory.build :bid_order + end + + test "refunding an order" do + @b.capture! + put :refund, :id => @b.id + assert_equal "refunded", @b.reload.state + assert_redirected_to admin_orders_url + end + +end diff --git a/test/functional/auctions_controller_test.rb b/test/functional/auctions_controller_test.rb new file mode 100644 index 0000000..e2bcb96 --- /dev/null +++ b/test/functional/auctions_controller_test.rb @@ -0,0 +1,17 @@ +require 'test_helper' + +class AuctionsControllerTest < ActionController::TestCase + + # If this fails you need to seed the test database beforehand + test "homepage" do + get :index + assert_response :success, @response.body + end + + test "auction details" do + a = Factory :auction + get :show, :id => a.id + assert_response :success, @response.body + end + +end diff --git a/test/functional/bid_bots_controller_test.rb b/test/functional/bid_bots_controller_test.rb new file mode 100644 index 0000000..e97d696 --- /dev/null +++ b/test/functional/bid_bots_controller_test.rb @@ -0,0 +1,24 @@ +require 'test_helper' + +class BidBotsControllerTest < ActionController::TestCase + + test "redirected if logged out" do + flunk + post :create + assert_response :redirect, @response.body + end + + test "bot is created if it does not exist" do + flunk + u = Factory(:account) + a = Factory(:auction) + AccountSession(u) + post :create, {:bid_bot => {:bids_left => 5, :bid_from => 0}, :auction_id => a.id} + assert_response :success, @response.body + end + + test "bot destroyed if it existed" do + flunk + end + +end diff --git a/test/functional/bookmarks_controller_test.rb b/test/functional/bookmarks_controller_test.rb new file mode 100644 index 0000000..b92109b --- /dev/null +++ b/test/functional/bookmarks_controller_test.rb @@ -0,0 +1,26 @@ +require 'test_helper' + +class BookmarksControllerTest < ActionController::TestCase + setup :activate_authlogic + + test "watch a new auction and existing auction" do + u = Factory :account + a = Factory :auction + AccountSession.create u + 2.times do + post :create, :auction_id => a.id + assert_response :redirect + assert_redirected_to bookmarks_url + end + end + + test "delete an existing auction and bogus auction" do + u = Factory :account + a = Factory :auction + AccountSession.create u + b = Bookmark.create :account => u, :auction => a + delete :destroy, :id => a.id + assert_redirected_to bookmarks_url + end + +end diff --git a/test/functional/contacts_controller_test.rb b/test/functional/contacts_controller_test.rb new file mode 100644 index 0000000..e7ef662 --- /dev/null +++ b/test/functional/contacts_controller_test.rb @@ -0,0 +1,23 @@ +require 'test_helper' + +class ContactsControllerTest < ActionController::TestCase + + test "get to new contact page" do + get :show + assert_response :success + assert_not_nil :contact + end + + test "good contact sends email and redirects to home" do + post :create, :contact => Factory.attributes_for(:contact) + assert_redirected_to root_url + end + + test "bad contact renders show" do + post :create, :contact => Factory.attributes_for(:contact, :email => "") + assert_response :success + assert_template :show + assert_not_nil :contact + end + +end diff --git a/test/functional/landings_controller_test.rb b/test/functional/landings_controller_test.rb new file mode 100644 index 0000000..744d727 --- /dev/null +++ b/test/functional/landings_controller_test.rb @@ -0,0 +1,30 @@ +require 'test_helper' + +class LandingsControllerTest < ActionController::TestCase + + test "no auction for product redirects" do + p = Factory :product + get :show, :id => p.id + assert_response :redirect + end + + test "active auction renders active" do + p = Factory :product + a = Factory :auction, :product => p + get :show, :id => p.id + assert_response :success + assert_template :active + assert_not_nil :auction + assert_not_nil :product + end + + test "finished auction renders finished" do + p = Factory :product + a = Factory :auction, :product => p, :ending_at => 1.second.from_now + sleep(1) + get :show, :id => p.id + assert_response :success + assert_template :finished + end + +end diff --git a/test/functional/orders_controller_test.rb b/test/functional/orders_controller_test.rb new file mode 100644 index 0000000..34c25bf --- /dev/null +++ b/test/functional/orders_controller_test.rb @@ -0,0 +1,10 @@ +require 'test_helper' + +class OrdersControllerTest < ActionController::TestCase + + test "blank orders should redirect" do + get :index + assert_response :redirect, @response.body + end + +end diff --git a/test/functional/password_resets_controller_test.rb b/test/functional/password_resets_controller_test.rb new file mode 100644 index 0000000..9626cd6 --- /dev/null +++ b/test/functional/password_resets_controller_test.rb @@ -0,0 +1,38 @@ +require 'test_helper' + +class PasswordResetsControllerTest < ActionController::TestCase + setup :activate_authlogic + + test "request a password reset with a valid account" do + x = Factory :account + post :create, :email => x.email + assert_response :redirect, @response.body + assert_not_nil flash.notice, flash.inspect + end + + test "request a password reset with an invalid account" do + post :create, :email => "fake@fake.com" + assert_response :success, @response.body + assert_template :new + assert_equal I18n.t("flash.password_reset.no_account"), flash.alert + end + + test "get to password change screen with good code" do + x = Factory :account + get :edit, :code => x.perishable_token + assert_response :success, @response.body + end + + test "redirect if code is bad" do + get :edit, :code => "invalid" + assert_response :redirect, @response.body + end + + test "update password" do + x = Factory :account + put :update, :code => x.perishable_token, :account => {:password => "foobar", :password_confirmation => "foobar"} + assert_equal x.password, "foobar" + assert_response :redirect, @response.body + end + +end diff --git a/test/functional/static_controller_test.rb b/test/functional/static_controller_test.rb new file mode 100644 index 0000000..c92805d --- /dev/null +++ b/test/functional/static_controller_test.rb @@ -0,0 +1,12 @@ +require 'test_helper' + +class StaticControllerTest < ActionController::TestCase + + test "all pages return 200" do + [:privacy, :faq, :about, :tos, :returns, :rewards, :guarantee, :tips].each do |page| + get page + assert_response :success + end + end + +end diff --git a/test/integration/metal_test.rb b/test/integration/metal_test.rb new file mode 100644 index 0000000..2ec2968 --- /dev/null +++ b/test/integration/metal_test.rb @@ -0,0 +1,24 @@ +require 'test_helper' + +class MetalTest < ActionDispatch::IntegrationTest + + def setup + 5.times {Factory :auction} + end + + test "get widget" do + # get "/promos/init", :auctions => "[]", :widgets => "[]", :callback => "function123" + #assert_response :success + get "/promos/#{Auction.last.id}", :t => 123456789 + assert_response :success + end + + test "get poll" do + ids = Auction.all.collect(&:id) + get "/poller", :ids => ids.join("-"), :u => "null", :t => 123456789 + assert_response :success + get "/poller/#{ids.first}", :u => "null", :t => 123456789 + assert_response :success + end + +end diff --git a/test/performance/browsing_test.rb b/test/performance/browsing_test.rb new file mode 100644 index 0000000..867fc8c --- /dev/null +++ b/test/performance/browsing_test.rb @@ -0,0 +1,9 @@ +require 'test_helper' +require 'rails/performance_test_help' + +# Profiling results for each test method are written to tmp/performance. +class BrowsingTest < ActionDispatch::PerformanceTest + def test_homepage + get '/' + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb new file mode 100644 index 0000000..550ccc4 --- /dev/null +++ b/test/test_helper.rb @@ -0,0 +1,43 @@ +ENV["RAILS_ENV"] = "test" +require File.expand_path('../../config/environment', __FILE__) +require 'rails/test_help' +require "authlogic/test_case" +require "#{Rails.root}/db/seeds.rb" + +Jammit.load_configuration("#{Rails.root}/config/assets.yml") + +class ActiveSupport::TestCase + + # Shortcut to bid on an auction. Creates user and auction if not supplied + def assert_bid(user = nil, auction = nil, msg = "Could not bid") + user ||= Factory :account, :credits => 500 + auction ||= Factory :auction + bid = Bid.new(:account => user, :auction => auction) + saved = bid.save + assert_block "#{msg}: #{bid.errors[:base]}" do + saved + end + end + + def bid!(user, auction) + Bid.create!(:account => user, :auction => auction) + end + + def assert_no_bid(user = nil, auction = nil, msg = "Should not have bid") + user ||= Factory :account + auction ||= Factory :auction + assert_block msg do + not Bid.new(:account => user, :auction => auction).save + end + end + + # Fast forward to a little after the auction has ended + def finish(auction) + Timecop.travel(auction.ending_at + 1.second) + end + + def assert_logged_out + assert_nil controller.session["user_credentials"] + end + +end diff --git a/test/unit/account_test.rb b/test/unit/account_test.rb new file mode 100644 index 0000000..371b29f --- /dev/null +++ b/test/unit/account_test.rb @@ -0,0 +1,105 @@ +require 'test_helper' + +class AccountTest < ActiveSupport::TestCase + + test "search by various items" do + a = Factory :account, :source => "dailymakeover" + assert Account.search(a.username).present? + assert Account.search(a.email).present? + assert Account.search(a.source).present? + end + + test "search with blank shows all" do + 2.times {Factory :account} + assert_equal Account.search("").size, 2 + end + + test "winnings expire" do + u = Factory :account + a = Factory :auction, :account => u + Timecop.travel(a.ending_at + Rails.configuration.won_auction_expiration) + assert_equal 0, u.winnings.size + end + + test "active auctions should increase and expire" do + u = Factory :account, :credits => 5 + assert_bid u + assert_equal 1, u.active_auctions.count + Timecop.travel 1.day + assert_equal 0, u.active_auctions.reload.count + end + + test "wins this month" do + Timecop.freeze do + u = Factory :account, :credits => 5 + assert_bid u + Timecop.travel 1.day + assert_equal 1, u.wins_this_month.size + Timecop.travel 1.month + assert_equal 0, u.reload.wins_this_month.size, "wins should reset every month" + end + end + + test "wins today" do + Timecop.freeze do + u = Factory :account, :credits => 5 + assert_equal 0, u.wins_today.size + assert_bid u + Timecop.travel 2.hours + assert_equal 1, u.wins_today.size + Timecop.freeze(1.day.from_now.beginning_of_day) do + assert_equal 0, u.wins_today.size, "wins should reset at beginning of each day" + end + end + end + + test "already won auction of same product" do + Timecop.freeze do + u = Factory :account, :credits => 5 + a = Factory :auction + a2 = Factory :auction, :product => a.product + assert_bid u, a + Timecop.travel 2.hours + assert u.already_won?(a2) + assert_no_bid u, a2, "Shouldn't be able to bid on same product already won" + end + end + + test "usernames are alphanumeric" do + x = ->(name) {Factory.build(:account, :username => name).invalid?} + assert x.call("Larry.Bean") + assert x.call("Larry Bean") + assert x.call("Larry_7") + assert !x.call("grapes2") + end + + test "beginner?" do + u = Factory :account, :credits => 5 + assert u.beginner? + assert_bid u + Timecop.travel 2.hours + assert !u.reload.beginner?, "not a beginner, already won" + end + + test "awarding bids increments cumulative bids too" do + u = Factory.build :account, :credits => 0, :bonuses => 0 + x = u.award :credits, 5 + assert_equal u, x, "should return self" + assert_equal 5, u.credits + assert_equal 5, u.cumulative_credits + u.award :bonuses, 3 + assert_equal 3, u.bonuses + assert_equal 3, u.cumulative_bonuses + end + + test "active bots" do + Timecop.freeze do + u = Factory :account, :credits => 5 + bot = Factory :bid_bot, :account => u + assert_equal 1, u.active_bots.size + Timecop.travel 2.hours + assert_equal 0, u.active_bots.size + end + end + +end diff --git a/test/unit/auction_test.rb b/test/unit/auction_test.rb new file mode 100644 index 0000000..b586ec3 --- /dev/null +++ b/test/unit/auction_test.rb @@ -0,0 +1,50 @@ +require 'test_helper' + +class AuctionTest < ActiveSupport::TestCase + + def setup + Auction.destroy_all + end + + test "do not show beginner auctions in history" do + assert_no_difference 'Auction.history.size' do + a = Factory :auction, :beginner => true + finish a + end + end + + test "beginner auctions only visible to logged in customers who haven't won anything" do + u = Factory :account, :credits => 1 + a = Factory :auction, :beginner => true + a2 = Factory :auction, :beginner => true, :ending_in => 5.hours + assert Auction.for_user(nil).empty?, "not logged in, shouldnt see them" + assert Auction.for_user(u).present?, "beginner should see beginner auctions" + assert_bid u, a + finish a + assert !u.reload.beginner?, "no longer beginner" + assert Auction.for_user(u).reload.empty?, "not a beginner anymore. shouldn't see this" + end + + test "buy now price starts at retail" do + u1 = Factory :account, :credits => 10 + a = Factory :auction, :is_buy_now => true + assert_equal a.retail_price, a.buy_now_price(u1) + end + + test "bonus bids do not affect buy now price" do + u = Factory :account, :credits => 10, :bonuses => 2 + a = Factory :auction, :is_buy_now => true + assert_no_difference "a.reload.buy_now_price(u)" do + assert_bid u, a + end + end + + test "buy now price decreases by bid price" do + u = Factory :account, :credits => 10 + a = Factory :auction, :is_buy_now => true + assert_difference("a.reload.buy_now_price(u.reload)", Money.new(-75)) do + bid!(u, a) + end + end + +end diff --git a/test/unit/bid_bot_test.rb b/test/unit/bid_bot_test.rb new file mode 100644 index 0000000..9fb6b5f --- /dev/null +++ b/test/unit/bid_bot_test.rb @@ -0,0 +1,61 @@ +require 'test_helper' + +class BidBotTest < ActiveSupport::TestCase + + def setup + @user = Factory :account, :credits => 10 + end + + test "only one bid bot per user, per auction" do + bot = Factory :bid_bot, :account => @user + assert_raise ActiveRecord::RecordInvalid do # replace with RecordNotUnique once we allow > 1 active bots + Factory :bid_bot, :auction => bot.auction, :account => bot.account + end + end + + test "bids left always >= 0" do + assert_raise ActiveRecord::RecordInvalid do + Factory :bid_bot, :bids_left => -1, :account => @user + end + end + + test "bid from always >= 0" do + assert_raise ActiveRecord::RecordInvalid do + Factory :bid_bot, :bid_from => -1.to_money, :account => @user + end + end + + test "using a bid bot decreases bids left" do + bot = Factory :bid_bot, :account => @user + assert_difference "bot.bids_left", -1 do + bot.bid! + end + end + + test "Resque job performs a bid" do + b = Factory :bid_bot, :account => @user, :bid_from_in_cents => 0 + assert_difference "b.auction.reload.going_price.cents", 1 do + BidBot.perform(b.auction_id) + end + end + + test "bots count towards active auctions" do + assert_difference("@user.active_auctions.size", 1) do + Factory :bid_bot, :account => @user + end + end + + test "deleting unused bot decreases active auctions" do + b = Factory :bid_bot, :account => @user + assert_difference("@user.active_auctions.size", -1) do + b.destroy + end + end + + test "only one active bot per user" do + Factory :bid_bot, :account => @user + assert_raise ActiveRecord::RecordInvalid do + Factory :bid_bot, :account => @user + end + end +end diff --git a/test/unit/bid_test.rb b/test/unit/bid_test.rb new file mode 100644 index 0000000..3e3b9c2 --- /dev/null +++ b/test/unit/bid_test.rb @@ -0,0 +1,55 @@ +require 'test_helper' + +class BidTest < ActiveSupport::TestCase + + # Rewrite this + test "cannot participate in more active auctions than win limit permits" do + u = Factory :account, :credits => 500 + Rails.configuration.daily_win_limit.times do + assert_bid u + end + assert_no_bid u, nil, "reached potential win limit" + end + + test "daily win limits" do + u = Factory :account, :credits => 500 + Rails.configuration.daily_win_limit.times do + assert_bid u, nil, "should go through" + end + assert_no_bid u, nil, "reached daily win limit" + a = Factory :auction, :ending_at => 2.days.from_now + Timecop.travel 1.day + assert_equal 0, u.wins_today.size + assert_equal 3, u.wins_this_month.size + assert_bid u, a, "new day. should go through." + end + + test "can win only one of same expensive product" do + u = Factory :account, :credits => 500 + a = Factory :auction, :retail_price => Rails.configuration.price_threshold + a2 = Factory :auction, :retail_price => Rails.configuration.price_threshold, :ending_in => 5.days, :product => a.product + assert_bid u, a + finish a + assert_no_bid u, a2, "user shouldn't be able to win this again" + end + + test "can compete in beginner auctions only if you have not won anything" do + u = Factory :account, :credits => 500 + a = Factory :auction, :beginner => true + a2 = Factory :auction, :beginner => true, :ending_in => 5.days + assert_bid u, a + Timecop.travel 2.hours + assert_no_bid u, a2 + end + + test "can compete in only 1 beginner auction at a time" do + u = Factory :account, :credits => 500 + a = Factory :auction, :beginner => true + a2 = Factory :auction, :beginner => true + a3 = Factory :auction + assert_bid u, a + assert_no_bid u, a2 + assert_bid u, a3 + end + +end diff --git a/test/unit/order_test.rb b/test/unit/order_test.rb new file mode 100644 index 0000000..70a096c --- /dev/null +++ b/test/unit/order_test.rb @@ -0,0 +1,16 @@ +require 'test_helper' + +class OrderTest < ActiveSupport::TestCase + + test "searching orders in admin" do + Order.destroy_all + a = Factory :account + 5.times {Factory :bid_order, :state => "complete", :account => a} + 2.times {Factory :bid_order, :state => "refunded"} + assert_equal 5, Order.search(:complete).size + assert_equal 2, Order.search(:refunded).size + assert_equal 5, Order.search(:complete, a.username).size + assert_equal 0, Order.search(:refunded, a.username).size + end + +end \ No newline at end of file diff --git a/vendor/plugins/.gitkeep b/vendor/plugins/.gitkeep new file mode 100644 index 0000000..e69de29