diff --git a/.gitignore b/.gitignore index ae8292f38..b16db903e 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ capybara-*.html /tmp /db/*.sqlite3 /public/system +/public/assets /coverage/ /spec/tmp **.orig diff --git a/Gemfile b/Gemfile index d29fa223b..d616cb534 100644 --- a/Gemfile +++ b/Gemfile @@ -8,7 +8,7 @@ end if Bundler::VERSION < '2' source 'https://rubygems.org' # core -gem 'rails', '4.2.4' # when update, all initializers eis_custom files needs check/update +gem 'rails', '4.2.5.2' # when update, all initializers eis_custom files needs check/update gem 'iso8601', '0.8.6' # for dates and times gem 'hashie-forbidden_attributes', '0.1.1' gem 'SyslogLogger', '2.0', require: 'syslog/logger' @@ -31,17 +31,17 @@ gem 'rails-settings-cached', '0.4.1' # for settings # html-xml gem 'haml-rails', '0.9.0' # haml for views -gem 'nokogiri', '1.6.6.2' # For XML parsing +gem 'nokogiri', '1.6.7.2' # For XML parsing # style gem 'sass-rails', '5.0.3' # sass style gem 'bootstrap-sass', '3.3.5.1' # bootstrap style # js -gem 'uglifier', '2.7.1' # minifies js +gem 'uglifier', '2.7.2' # minifies js gem 'coffee-rails', '4.1.0' # coffeescript support gem 'turbolinks', '2.5.3' # faster page load -gem 'jquery-rails', '4.0.3' # jquery +gem 'jquery-rails', '4.0.4' # jquery gem 'selectize-rails', '0.12.1' # include selectize.js for select gem 'therubyracer', '0.12.2', platforms: :ruby gem 'jquery-validation-rails', '1.13.1' # validate on client side @@ -56,7 +56,7 @@ gem 'bootstrap-datepicker-rails', '1.3.1.1' # datepicker gem 'liquid', '3.0.6' # for email templates # rights -gem 'devise', '3.5.1' # authenitcation +gem 'devise', '3.5.4' # authenitcation gem 'cancancan', '1.11.0' # autharization # rest api diff --git a/Gemfile.lock b/Gemfile.lock index 45eb09943..dbc1e8e3c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -50,38 +50,38 @@ GEM specs: SyslogLogger (2.0) abstract_type (0.0.7) - actionmailer (4.2.4) - actionpack (= 4.2.4) - actionview (= 4.2.4) - activejob (= 4.2.4) + actionmailer (4.2.5.2) + actionpack (= 4.2.5.2) + actionview (= 4.2.5.2) + activejob (= 4.2.5.2) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 1.0, >= 1.0.5) - actionpack (4.2.4) - actionview (= 4.2.4) - activesupport (= 4.2.4) + actionpack (4.2.5.2) + actionview (= 4.2.5.2) + activesupport (= 4.2.5.2) rack (~> 1.6) rack-test (~> 0.6.2) rails-dom-testing (~> 1.0, >= 1.0.5) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (4.2.4) - activesupport (= 4.2.4) + actionview (4.2.5.2) + activesupport (= 4.2.5.2) builder (~> 3.1) erubis (~> 2.7.0) rails-dom-testing (~> 1.0, >= 1.0.5) rails-html-sanitizer (~> 1.0, >= 1.0.2) - activejob (4.2.4) - activesupport (= 4.2.4) + activejob (4.2.5.2) + activesupport (= 4.2.5.2) globalid (>= 0.3.0) - activemodel (4.2.4) - activesupport (= 4.2.4) + activemodel (4.2.5.2) + activesupport (= 4.2.5.2) builder (~> 3.1) - activerecord (4.2.4) - activemodel (= 4.2.4) - activesupport (= 4.2.4) + activerecord (4.2.5.2) + activemodel (= 4.2.5.2) + activesupport (= 4.2.5.2) arel (~> 6.0) activerecord-import (0.7.0) activerecord (>= 3.0) - activesupport (4.2.4) + activesupport (4.2.5.2) i18n (~> 0.7) json (~> 1.7, >= 1.7.7) minitest (~> 5.1) @@ -157,6 +157,7 @@ GEM concord (0.1.5) adamantium (~> 0.2.0) equalizer (~> 0.0.9) + concurrent-ruby (1.0.1) countries (0.11.4) currencies (~> 0.4.2) i18n_data (~> 0.7.0) @@ -173,7 +174,7 @@ GEM activerecord (>= 3.1.0, < 5.0.0) descendants_tracker (0.0.4) thread_safe (~> 0.3, >= 0.3.1) - devise (3.5.1) + devise (3.5.4) bcrypt (~> 3.0) orm_adapter (~> 0.1) railties (>= 3.2.6, < 5) @@ -276,7 +277,7 @@ GEM jbuilder (2.2.16) activesupport (>= 3.0.0, < 5) multi_json (~> 1.2) - jquery-rails (4.0.3) + jquery-rails (4.0.4) rails-dom-testing (~> 1.0) railties (>= 4.2.0) thor (>= 0.14, < 2.0) @@ -306,12 +307,12 @@ GEM memoizable (0.4.2) thread_safe (~> 0.3, >= 0.3.1) method_source (0.8.2) - mime-types (2.6.1) + mime-types (2.99.1) mina (0.3.1) open4 (~> 1.3.4) rake - mini_portile (0.6.2) - minitest (5.8.0) + mini_portile2 (2.0.0) + minitest (5.8.4) monetize (1.1.0) money (~> 6.5.0) money (6.5.1) @@ -326,8 +327,8 @@ GEM nenv (0.2.0) netrc (0.11.0) newrelic_rpm (3.12.0.288) - nokogiri (1.6.6.2) - mini_portile (~> 0.6.0) + nokogiri (1.6.7.2) + mini_portile2 (~> 2.0.0.rc2) nori (2.6.0) notiffany (0.0.7) nenv (~> 0.1) @@ -370,16 +371,16 @@ GEM rack-test (0.6.3) rack (>= 1.0) railroady (1.3.0) - rails (4.2.4) - actionmailer (= 4.2.4) - actionpack (= 4.2.4) - actionview (= 4.2.4) - activejob (= 4.2.4) - activemodel (= 4.2.4) - activerecord (= 4.2.4) - activesupport (= 4.2.4) + rails (4.2.5.2) + actionmailer (= 4.2.5.2) + actionpack (= 4.2.5.2) + actionview (= 4.2.5.2) + activejob (= 4.2.5.2) + activemodel (= 4.2.5.2) + activerecord (= 4.2.5.2) + activesupport (= 4.2.5.2) bundler (>= 1.3.0, < 2.0) - railties (= 4.2.4) + railties (= 4.2.5.2) sprockets-rails rails-deprecated_sanitizer (1.0.3) activesupport (>= 4.2.0.alpha) @@ -387,18 +388,18 @@ GEM activesupport (>= 4.2.0.beta, < 5.0) nokogiri (~> 1.6.0) rails-deprecated_sanitizer (>= 1.0.1) - rails-html-sanitizer (1.0.2) + rails-html-sanitizer (1.0.3) loofah (~> 2.0) rails-settings-cached (0.4.1) rails (>= 4.0.0) - railties (4.2.4) - actionpack (= 4.2.4) - activesupport (= 4.2.4) + railties (4.2.5.2) + actionpack (= 4.2.5.2) + activesupport (= 4.2.5.2) rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) rainbow (2.0.0) raindrops (0.15.0) - rake (10.4.2) + rake (10.5.0) ransack (1.5.1) actionpack (>= 3.0) activerecord (>= 3.0) @@ -415,8 +416,8 @@ GEM unparser (~> 0.2.2) ref (2.0.0) request_store (1.1.0) - responders (2.1.0) - railties (>= 4.2.0, < 5) + responders (2.1.1) + railties (>= 4.2.0, < 5.1) rest-client (1.8.0) http-cookie (>= 1.0.2, < 2.0) mime-types (>= 1.16, < 3.0) @@ -500,12 +501,13 @@ GEM spring (1.3.6) spring-commands-rspec (1.0.4) spring (>= 0.9.1) - sprockets (3.3.4) - rack (~> 1.0) - sprockets-rails (2.3.3) - actionpack (>= 3.0) - activesupport (>= 3.0) - sprockets (>= 2.8, < 4.0) + sprockets (3.5.2) + concurrent-ruby (~> 1.0) + rack (> 1, < 3) + sprockets-rails (3.0.4) + actionpack (>= 4.0) + activesupport (>= 4.0) + sprockets (>= 3.0.0) sys-uname (0.9.0) ffi (>= 1.0.0) terminal-table (1.5.2) @@ -521,7 +523,7 @@ GEM coffee-rails tzinfo (1.2.2) thread_safe (~> 0.1) - uglifier (2.7.1) + uglifier (2.7.2) execjs (>= 0.3.0) json (>= 1.8.0) unf (0.1.4) @@ -548,7 +550,7 @@ GEM coercible (~> 1.0) descendants_tracker (~> 0.0, >= 0.0.3) equalizer (~> 0.0, >= 0.0.9) - warden (1.2.3) + warden (1.2.6) rack (>= 1.0) wasabi (3.5.0) httpi (~> 2.0) @@ -584,7 +586,7 @@ DEPENDENCIES data_migrate! database_cleaner (= 1.4.1) deep_cloneable (= 2.1.1) - devise (= 3.5.1) + devise (= 3.5.4) digidoc_client (= 0.2.1) epp (= 1.4.2)! epp-xml (= 1.0.4) @@ -603,7 +605,7 @@ DEPENDENCIES isikukood iso8601 (= 0.8.6) jbuilder (= 2.2.16) - jquery-rails (= 4.0.3) + jquery-rails (= 4.0.4) jquery-ui-rails (= 5.0.5) jquery-validation-rails (= 1.13.1) kaminari (= 0.16.3) @@ -612,7 +614,7 @@ DEPENDENCIES mina (= 0.3.1) money-rails (= 1.4.1) newrelic_rpm (= 3.12.0.288) - nokogiri (= 1.6.6.2) + nokogiri (= 1.6.7.2) nprogress-rails (= 0.1.6.7) paper_trail! pdfkit (= 0.6.2) @@ -625,7 +627,7 @@ DEPENDENCIES que-web (= 0.4.0) que_mailer! railroady (= 1.3.0) - rails (= 4.2.4) + rails (= 4.2.5.2) rails-settings-cached (= 0.4.1) rake ransack (= 1.5.1) @@ -645,7 +647,7 @@ DEPENDENCIES therubyracer (= 0.12.2) traceroute (= 0.5.0) turbolinks (= 2.5.3) - uglifier (= 2.7.1) + uglifier (= 2.7.2) unicorn uuidtools (= 2.1.5) validates_email_format_of (= 1.6.3) diff --git a/app/assets/javascripts/registrar/application.coffee b/app/assets/javascripts/registrar/application.coffee index 9dda64de6..a1a2084fe 100644 --- a/app/assets/javascripts/registrar/application.coffee +++ b/app/assets/javascripts/registrar/application.coffee @@ -27,3 +27,16 @@ $(document).on 'page:change', -> form.find('.js-ident-tip').show() $('.js-contact-form').trigger('restoreDefault') + + $('[data-legal-document]').each (i, fileInput)-> + minSize = 3 * 1024 # 3kB + maxSize = 8 * 1024 * 1024; # 8 MB + $(fileInput).closest('form').submit (e) -> + if (files = fileInput.files).length + fileSize = files[0].size + if fileSize < minSize + alert 'Document size should be more than 3kB' + return false + else if fileSize > maxSize + alert 'Document size should be less than 8MB' + return false diff --git a/app/controllers/admin/account_activities_controller.rb b/app/controllers/admin/account_activities_controller.rb index 0f095734f..4a4fe2307 100644 --- a/app/controllers/admin/account_activities_controller.rb +++ b/app/controllers/admin/account_activities_controller.rb @@ -1,8 +1,8 @@ class Admin::AccountActivitiesController < AdminController load_and_authorize_resource + before_action :set_default_dates, only: [:index] def index # rubocop: disable Metrics/AbcSize - params[:q] ||= {} ca_cache = params[:q][:created_at_lteq] begin @@ -25,10 +25,11 @@ class Admin::AccountActivitiesController < AdminController @account_activities = @q.result.page(params[:page]).per(params[:results_per_page]) sort = @account_activities.orders.map(&:to_sql).join(",") + # can do here inline SQL as it's our if params[:page] && params[:page].to_i > 1 - @sum = @q.result.reorder(sort).limit(@account_activities.offset_value) + @b.result.where.not(id: @q.result.map(&:id)) + @sum = @q.result.reorder(sort).limit(@account_activities.offset_value).sum(:sum) + @b.result.where("account_activities.id NOT IN (#{@q.result.select(:id).to_sql})").sum(:sum) else - @sum = @b.result.where.not(id: @q.result.map(&:id)) + @sum = @b.result.where("account_activities.id NOT IN (#{@q.result.select(:id).to_sql})").sum(:sum) end respond_to do |format| @@ -40,4 +41,20 @@ class Admin::AccountActivitiesController < AdminController params[:q][:created_at_lteq] = ca_cache end + + def set_default_dates + params[:q] ||= {} + + if params[:q][:created_at_gteq].nil? && params[:q][:created_at_lteq].nil? && params[:created_after].present? + + default_date = params[:created_after] + + if !['today', 'tomorrow', 'yesterday'].include?(default_date) + default_date = 'today' + end + + params[:q][:created_at_gteq] = Date.send(default_date).strftime("%Y-%m-%d") + end + + end end diff --git a/app/controllers/admin/blocked_domains_controller.rb b/app/controllers/admin/blocked_domains_controller.rb index 9394a9334..49cc65675 100644 --- a/app/controllers/admin/blocked_domains_controller.rb +++ b/app/controllers/admin/blocked_domains_controller.rb @@ -2,46 +2,54 @@ class Admin::BlockedDomainsController < AdminController load_and_authorize_resource def index - bd = BlockedDomain.pluck(:name) - if bd - @blocked_domains = bd.to_yaml.gsub("---\n", '').gsub("-", '').gsub(" ", '') - end + + params[:q] ||= {} + domains = BlockedDomain.all.order(:name) + @q = domains.search(params[:q]) + @domains = @q.result.page(params[:page]) + @domains = @domains.per(params[:results_per_page]) if params[:results_per_page].to_i > 0 + + end + + def new + + @domain = BlockedDomain.new + end def create - @blocked_domains = params[:blocked_domains] - begin - params[:blocked_domains] = "---\n" if params[:blocked_domains].blank? - names = YAML.load(params[:blocked_domains]) - fail if names == false - rescue - flash.now[:alert] = I18n.t('invalid_yaml') - logger.warn 'Invalid YAML' - render :index and return - end + @domain = BlockedDomain.new(blocked_domain_params) - names = names.split(' ') - result = true - BlockedDomain.transaction do - existing = BlockedDomain.any_of_domains(names).pluck(:id) - BlockedDomain.where.not(id: existing).destroy_all - - names.each do |name| - rec = BlockedDomain.find_or_initialize_by(name: name) - unless rec.save - result = false - raise ActiveRecord::Rollback - end - end - end - - if result - flash[:notice] = I18n.t('record_updated') - redirect_to :back + if @domain.save + flash[:notice] = I18n.t('domain_added') + redirect_to admin_blocked_domains_path else - flash.now[:alert] = I18n.t('failed_to_update_record') - render :index + flash.now[:alert] = I18n.t('failed_to_add_domain') + render 'new' + end + + end + + def delete + + if BlockedDomain.find(params[:id]).destroy + flash[:notice] = I18n.t('domain_deleted') + redirect_to admin_blocked_domains_path + else + flash.now[:alert] = I18n.t('failed_to_delete_domain') + redirect_to admin_blocked_domains_path end end -end + + + def blocked_domain_params + params.require(:blocked_domain).permit(:name) + end + + private + + def set_domain + @domain = BlockedDomain.find(params[:id]) + end +end \ No newline at end of file diff --git a/app/controllers/admin/contacts_controller.rb b/app/controllers/admin/contacts_controller.rb index 960d74002..3a05bb759 100644 --- a/app/controllers/admin/contacts_controller.rb +++ b/app/controllers/admin/contacts_controller.rb @@ -20,6 +20,8 @@ class Admin::ContactsController < AdminController else contacts = Contact.includes(:registrar) end + contacts = contacts.where("ident_country_code is null or ident_country_code=''") if params[:only_no_country_code].eql?('1') + normalize_search_parameters do @q = contacts.search(search_params) diff --git a/app/controllers/admin/epp_logs_controller.rb b/app/controllers/admin/epp_logs_controller.rb index deb9ee8e7..b14a99766 100644 --- a/app/controllers/admin/epp_logs_controller.rb +++ b/app/controllers/admin/epp_logs_controller.rb @@ -1,5 +1,6 @@ class Admin::EppLogsController < AdminController load_and_authorize_resource class: ApiLog::EppLog + before_action :set_default_dates, only: [:index] def index @q = ApiLog::EppLog.search(params[:q]) @@ -10,4 +11,19 @@ class Admin::EppLogsController < AdminController def show @epp_log = ApiLog::EppLog.find(params[:id]) end + + def set_default_dates + params[:q] ||= {} + + if params[:q][:created_at_gteq].nil? && params[:q][:created_at_lteq].nil? && params[:created_after].present? + default_date = params[:created_after] + + if !['today', 'tomorrow', 'yesterday'].include?(default_date) + default_date = 'today' + end + + params[:q][:created_at_gteq] = Date.send(default_date).strftime("%Y-%m-%d") + end + + end end diff --git a/app/controllers/admin/invoices_controller.rb b/app/controllers/admin/invoices_controller.rb index 5aa6d4438..709dc866a 100644 --- a/app/controllers/admin/invoices_controller.rb +++ b/app/controllers/admin/invoices_controller.rb @@ -23,7 +23,7 @@ class Admin::InvoicesController < AdminController def index @q = Invoice.includes(:account_activity).search(params[:q]) - @q.sorts = 'id desc' if @q.sorts.empty? + @q.sorts = 'number desc' if @q.sorts.empty? @invoices = @q.result.page(params[:page]) end diff --git a/app/controllers/admin/registrars_controller.rb b/app/controllers/admin/registrars_controller.rb index cf8c89505..be4b7d092 100644 --- a/app/controllers/admin/registrars_controller.rb +++ b/app/controllers/admin/registrars_controller.rb @@ -57,7 +57,7 @@ class Admin::RegistrarsController < AdminController def registrar_params params.require(:registrar).permit( :name, :reg_no, :vat_no, :street, :city, :state, :zip, :billing_address, - :country_code, :email, :phone, :billing_email, :code + :country_code, :email, :phone, :billing_email, :code, :test_registrar ) end end diff --git a/app/controllers/admin/repp_logs_controller.rb b/app/controllers/admin/repp_logs_controller.rb index e9e35aac0..8e904007a 100644 --- a/app/controllers/admin/repp_logs_controller.rb +++ b/app/controllers/admin/repp_logs_controller.rb @@ -1,5 +1,6 @@ class Admin::ReppLogsController < AdminController load_and_authorize_resource class: ApiLog::ReppLog + before_action :set_default_dates, only: [:index] def index @q = ApiLog::ReppLog.search(params[:q]) @@ -10,4 +11,20 @@ class Admin::ReppLogsController < AdminController def show @repp_log = ApiLog::ReppLog.find(params[:id]) end + + def set_default_dates + params[:q] ||= {} + + if params[:q][:created_at_gteq].nil? && params[:q][:created_at_lteq].nil? && params[:created_after].present? + + default_date = params[:created_after] + + if !['today', 'tomorrow', 'yesterday'].include?(default_date) + default_date = 'today' + end + + params[:q][:created_at_gteq] = Date.send(default_date).strftime("%Y-%m-%d") + end + + end end diff --git a/app/controllers/admin/reserved_domains_controller.rb b/app/controllers/admin/reserved_domains_controller.rb index 402d33022..7de8d9891 100644 --- a/app/controllers/admin/reserved_domains_controller.rb +++ b/app/controllers/admin/reserved_domains_controller.rb @@ -1,49 +1,68 @@ class Admin::ReservedDomainsController < AdminController load_and_authorize_resource + before_action :set_domain, only: [:edit, :update] def index - names = ReservedDomain.pluck(:name, :password).each_with_object({}){|domain, hash| hash[domain[0]] = domain[1]} - names.names = nil if names.blank? - @reserved_domains = names.to_yaml.gsub(/---.?\n/, '').gsub(/\.\.\..?\n/, '') + + params[:q] ||= {} + domains = ReservedDomain.all.order(:name) + @q = domains.search(params[:q]) + @domains = @q.result.page(params[:page]) + @domains = @domains.per(params[:results_per_page]) if params[:results_per_page].to_i > 0 + + end + + def new + @domain = ReservedDomain.new + end + + def edit end def create - @reserved_domains = params[:reserved_domains] - begin - params[:reserved_domains] = "---\n" if params[:reserved_domains].blank? - names = YAML.load(params[:reserved_domains]) - fail if names == false - rescue - flash.now[:alert] = I18n.t('invalid_yaml') - logger.warn 'Invalid YAML' - render :index and return - end + @domain = ReservedDomain.new(reserved_domain_params) - result = true - ReservedDomain.transaction do - # removing old ones - existing = ReservedDomain.any_of_domains(names.keys).pluck(:id) - ReservedDomain.where.not(id: existing).destroy_all - - #updating and adding - names.each do |name, psw| - rec = ReservedDomain.find_or_initialize_by(name: name) - rec.password = psw - - unless rec.save - result = false - raise ActiveRecord::Rollback - end - end - end - - if result - flash[:notice] = I18n.t('record_updated') - redirect_to :back + if @domain.save + flash[:notice] = I18n.t('domain_added') + redirect_to admin_reserved_domains_path else - flash.now[:alert] = I18n.t('failed_to_update_record') - render :index + flash.now[:alert] = I18n.t('failed_to_add_domain') + render 'new' end + + end + + def update + + if @domain.update(reserved_domain_params) + flash[:notice] = I18n.t('domain_updated') + else + flash.now[:alert] = I18n.t('failed_to_update_domain') + end + render 'edit' + + end + + def delete + + if ReservedDomain.find(params[:id]).destroy + flash[:notice] = I18n.t('domain_deleted') + redirect_to admin_reserved_domains_path + else + flash.now[:alert] = I18n.t('failed_to_delete_domain') + redirect_to admin_reserved_domains_path + end + + end + + private + + def reserved_domain_params + params.require(:reserved_domain).permit(:name, :password) + end + + def set_domain + @domain = ReservedDomain.find(params[:id]) end end diff --git a/app/controllers/admin/settings_controller.rb b/app/controllers/admin/settings_controller.rb index 89ccd9ac6..cc49b3b61 100644 --- a/app/controllers/admin/settings_controller.rb +++ b/app/controllers/admin/settings_controller.rb @@ -59,6 +59,7 @@ class Admin::SettingsController < AdminController :transfer_wait_time, :invoice_number_min, :invoice_number_max, + :days_to_keep_business_registry_cache, :days_to_keep_invoices_active, :days_to_keep_overdue_invoices_active, :days_to_renew_domain_before_expire, diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 5d051377d..ac26e61a3 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -32,7 +32,7 @@ class ApplicationController < ActionController::Base if registrar_request? registrar_root_url elsif registrant_request? - registrant_root_url + registrant_login_url elsif admin_request? admin_root_url end diff --git a/app/controllers/epp/contacts_controller.rb b/app/controllers/epp/contacts_controller.rb index 22473bae7..117aaabc0 100644 --- a/app/controllers/epp/contacts_controller.rb +++ b/app/controllers/epp/contacts_controller.rb @@ -19,6 +19,8 @@ class Epp::ContactsController < EppController authorize! :create, Epp::Contact @contact = Epp::Contact.new(params[:parsed_frame], current_user.registrar) + @contact.add_legal_file_to_new(params[:parsed_frame]) + if @contact.save render_epp_response '/epp/contacts/create' else @@ -39,7 +41,7 @@ class Epp::ContactsController < EppController def delete authorize! :delete, @contact, @password - if @contact.destroy_and_clean + if @contact.destroy_and_clean(params[:parsed_frame]) render_epp_response '/epp/contacts/delete' else handle_errors(@contact) diff --git a/app/controllers/epp/domains_controller.rb b/app/controllers/epp/domains_controller.rb index 91ddeb93d..fb3441580 100644 --- a/app/controllers/epp/domains_controller.rb +++ b/app/controllers/epp/domains_controller.rb @@ -30,6 +30,8 @@ class Epp::DomainsController < EppController handle_errors and return unless balance_ok?('create') # loads pricelist in this method ActiveRecord::Base.transaction do + @domain.add_legal_file_to_new(params[:parsed_frame]) + if @domain.save # TODO: Maybe use validate: false here because we have already validated the domain? current_user.registrar.debit!({ sum: @domain_pricelist.price.amount, diff --git a/app/controllers/epp_controller.rb b/app/controllers/epp_controller.rb index a0e7d7dce..49be47848 100644 --- a/app/controllers/epp_controller.rb +++ b/app/controllers/epp_controller.rb @@ -361,9 +361,10 @@ class EppController < ApplicationController if request_command == 'login' && frame.present? frame.gsub!(/pw>.+<\//, 'pw>[FILTERED]]+)>([^<])+<\/eis:legalDocument>/, "[FILTERED]") ApiLog::EppLog.create({ - request: frame, + request: trimmed_request, request_command: request_command, request_successful: epp_errors.empty?, request_object: params[:epp_object_type], diff --git a/app/controllers/registrant/contacts_controller.rb b/app/controllers/registrant/contacts_controller.rb new file mode 100644 index 000000000..db6c279eb --- /dev/null +++ b/app/controllers/registrant/contacts_controller.rb @@ -0,0 +1,26 @@ +class Registrant::ContactsController < RegistrantController + helper_method :domain_ids + def show + @contact = Contact.where(id: contacts).find_by(id: params[:id]) + @current_user = current_user + + authorize! :read, @contact + end + + def contacts + begin + DomainContact.where(domain_id: domain_ids).pluck(:contact_id) | Domain.where(id: domain_ids).pluck(:registrant_id) + rescue Soap::Arireg::NotAvailableError => error + flash[:notice] = I18n.t(error.json[:message]) + Rails.logger.fatal("[EXCEPTION] #{error.to_s}") + [] + end + end + + def domain_ids + @domain_ids ||= begin + ident_cc, ident = @current_user.registrant_ident.to_s.split '-' + BusinessRegistryCache.fetch_by_ident_and_cc(ident, ident_cc).associated_domain_ids + end + end +end \ No newline at end of file diff --git a/app/controllers/registrant/domains_controller.rb b/app/controllers/registrant/domains_controller.rb index 4bba945a8..fbd0eff13 100644 --- a/app/controllers/registrant/domains_controller.rb +++ b/app/controllers/registrant/domains_controller.rb @@ -1,5 +1,86 @@ class Registrant::DomainsController < RegistrantController + def index - authorize! :view, :registrant_domains + authorize! :view, :registrant_domains + params[:q] ||= {} + normalize_search_parameters do + @q = domains.search(params[:q]) + @domains = @q.result.page(params[:page]) end -end + @domains = @domains.per(params[:results_per_page]) if params[:results_per_page].to_i > 0 + end + + def show + @domain = domains.find(params[:id]) + authorize! :read, @domain + end + + def set_domain + @domain = domains.find(params[:id]) + end + + def domain_verification_url + authorize! :view, :registrant_domains + dom = domains.find(params[:id]) + if (dom.statuses.include?(DomainStatus::PENDING_UPDATE) || dom.statuses.include?(DomainStatus::PENDING_DELETE_CONFIRMATION)) && + dom.pending_json.present? + + @domain = dom + confirm_path = get_confirm_path(dom.statuses) + @verification_url = "#{confirm_path}/#{@domain.id}?token=#{@domain.registrant_verification_token}" + + else + flash[:warning] = I18n.t('available_verification_url_not_found') + redirect_to registrant_domain_path(dom.id) + end + end + + def download_list + authorize! :view, :registrant_domains + params[:q] ||= {} + normalize_search_parameters do + @q = domains.search(params[:q]) + @domains = @q + end + + respond_to do |format| + format.csv { render text: @domains.result.to_csv } + format.pdf do + pdf = @domains.result.pdf(render_to_string('registrant/domains/download_list', layout: false)) + send_data pdf, filename: 'domains.pdf' + end + end + end + + def domains + ident_cc, ident = @current_user.registrant_ident.split '-' + begin + BusinessRegistryCache.fetch_associated_domains ident, ident_cc + rescue Soap::Arireg::NotAvailableError => error + flash[:notice] = I18n.t(error.json[:message]) + Rails.logger.fatal("[EXCEPTION] #{error.to_s}") + current_user.domains + end + end + + def normalize_search_parameters + ca_cache = params[:q][:valid_to_lteq] + begin + end_time = params[:q][:valid_to_lteq].try(:to_date) + params[:q][:valid_to_lteq] = end_time.try(:end_of_day) + rescue + logger.warn('Invalid date') + end + yield + params[:q][:valid_to_lteq] = ca_cache + end + + def get_confirm_path(statuses) + if statuses.include?(DomainStatus::PENDING_UPDATE) + "#{ENV['registrant_url']}/registrant/domain_update_confirms" + elsif statuses.include?(DomainStatus::PENDING_DELETE_CONFIRMATION) + "#{ENV['registrant_url']}/registrant/domain_delete_confirms" + end + end + +end \ No newline at end of file diff --git a/app/controllers/registrant/registrars_controller.rb b/app/controllers/registrant/registrars_controller.rb new file mode 100644 index 000000000..d0630b73a --- /dev/null +++ b/app/controllers/registrant/registrars_controller.rb @@ -0,0 +1,7 @@ +class Registrant::RegistrarsController < RegistrantController + + def show + @registrar = Registrar.find(params[:id]) + authorize! :read, @registrar + end +end diff --git a/app/controllers/registrant/sessions_controller.rb b/app/controllers/registrant/sessions_controller.rb index f0a292137..91589d510 100644 --- a/app/controllers/registrant/sessions_controller.rb +++ b/app/controllers/registrant/sessions_controller.rb @@ -6,15 +6,10 @@ class Registrant::SessionsController < Devise::SessionsController # rubocop: disable Metrics/AbcSize def id - if Rails.env.development? - sign_in(RegistrantUser.find_or_create_by_idc_data('test'), event: :authentication) - return redirect_to registrant_root_url - end + id_code, id_issuer = request.env['SSL_CLIENT_S_DN'], request.env['SSL_CLIENT_I_DN_O'] + id_code, id_issuer = 'test', RegistrantUser::ACCEPTED_ISSUER if Rails.env.development? - logger.error request.env['SSL_CLIENT_S_DN'] - logger.error request.env['SSL_CLIENT_S_DN'].encoding - logger.error request.env['SSL_CLIENT_I_DN_O'] - @user = RegistrantUser.find_or_create_by_idc_data(request.env['SSL_CLIENT_S_DN'], request.env['SSL_CLIENT_I_DN_O']) + @user = RegistrantUser.find_or_create_by_idc_data(id_code, id_issuer) if @user sign_in(@user, event: :authentication) redirect_to registrant_root_url diff --git a/app/controllers/registrant/whois_controller.rb b/app/controllers/registrant/whois_controller.rb index 71d29dd76..b44a0bb67 100644 --- a/app/controllers/registrant/whois_controller.rb +++ b/app/controllers/registrant/whois_controller.rb @@ -1,5 +1,9 @@ class Registrant::WhoisController < RegistrantController def index authorize! :view, :registrant_whois + + if params[:domain_name].present? + @domain = WhoisRecord.find_by(name: params[:domain_name]); + end end end diff --git a/app/jobs/domain_delete_job.rb b/app/jobs/domain_delete_job.rb new file mode 100644 index 000000000..7d86e9885 --- /dev/null +++ b/app/jobs/domain_delete_job.rb @@ -0,0 +1,17 @@ +class DomainDeleteJob < Que::Job + + def run(domain_id) + domain = Domain.find(domain_id) + + ::PaperTrail.whodunnit = "job - #{self.class.name}" + WhoisRecord.where(domain_id: domain.id).destroy_all + + domain.destroy + bye_bye = domain.versions.last + domain.registrar.messages.create!( + body: "#{I18n.t(:domain_deleted)}: #{domain.name}", + attached_obj_id: bye_bye.id, + attached_obj_type: bye_bye.class.to_s + ) + end +end diff --git a/app/jobs/domain_set_delete_candidate_job.rb b/app/jobs/domain_set_delete_candidate_job.rb new file mode 100644 index 000000000..f1e489694 --- /dev/null +++ b/app/jobs/domain_set_delete_candidate_job.rb @@ -0,0 +1,10 @@ +class DomainSetDeleteCandidateJob < Que::Job + + def run(domain_id) + domain = Domain.find(domain_id) + domain.statuses << DomainStatus::DELETE_CANDIDATE + ::PaperTrail.whodunnit = "job - #{self.class.name}" + domain.save(validate: false) + DomainDeleteJob.enqueue(domain.id, run_at: rand(((24*60) - (DateTime.now.hour * 60 + DateTime.now.minute))).minutes.from_now) + end +end diff --git a/app/jobs/regenerate_registrar_whoises_job.rb b/app/jobs/regenerate_registrar_whoises_job.rb index 10e13a038..c5db82378 100644 --- a/app/jobs/regenerate_registrar_whoises_job.rb +++ b/app/jobs/regenerate_registrar_whoises_job.rb @@ -3,8 +3,8 @@ class RegenerateRegistrarWhoisesJob < Que::Job # no return as we want restart job if fails registrar = Registrar.find(registrar_id) - registrar.whois_records.select(:id).find_in_batches(batch_size: 20) do |group| - RegenerateWhoisRecordJob.enqueue group.map(&:id) + registrar.whois_records.select(:name).find_in_batches(batch_size: 20) do |group| + UpdateWhoisRecordJob.enqueue group.map(&:name), 'domain' end end end \ No newline at end of file diff --git a/app/jobs/regenerate_whois_record_job.rb b/app/jobs/regenerate_whois_record_job.rb deleted file mode 100644 index 6d79e2ea5..000000000 --- a/app/jobs/regenerate_whois_record_job.rb +++ /dev/null @@ -1,10 +0,0 @@ -class RegenerateWhoisRecordJob < Que::Job - def run(ids) - ids.each do |id| - record = WhoisRecord.find_by(id: id) - return unless record - - record.save - end - end -end \ No newline at end of file diff --git a/app/jobs/update_whois_record_job.rb b/app/jobs/update_whois_record_job.rb index b7edb1fdd..71f2b7e19 100644 --- a/app/jobs/update_whois_record_job.rb +++ b/app/jobs/update_whois_record_job.rb @@ -1,16 +1,52 @@ class UpdateWhoisRecordJob < Que::Job - def run(ids, type) + def run(names, type) klass = case type when 'reserved'then ReservedDomain when 'blocked' then BlockedDomain - else Domain + when 'domain' then Domain end - ids.each do |id| - record = klass.find_by(id: id) - next unless record - record.update_whois_record + Array(names).each do |name| + record = klass.find_by(name: name) + if record + send "update_#{type}", record + else + send "delete_#{type}", name + end end end + + + + def update_domain(domain) + domain.whois_record ? domain.whois_record.save : domain.create_whois_record + end + + def update_reserved(record) + record.generate_data + end + + def update_blocked(record) + update_reserved(record) + end + + + # 1. deleting own + # 2. trying to regenerate reserved in order domain is still in the list + def delete_domain(name) + WhoisRecord.where(name: name).destroy_all + + BlockedDomain.find_by(name: name).try(:generate_data) + ReservedDomain.find_by(name: name).try(:generate_data) + end + + def delete_reserved(name) + Domain.where(name: name).any? + Whois::Record.where(name: name).delete_all + end + + def delete_blocked(name) + delete_reserved(name) + end end \ No newline at end of file diff --git a/app/models/ability.rb b/app/models/ability.rb index cf98cb704..61f1edb2e 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -16,7 +16,7 @@ class Ability @user.roles.each { |role| send(role) } if @user.roles when 'ApiUser' @user.roles.each { |role| send(role) } if @user.roles - when 'RegistrantUser' + when 'RegistrantUser' static_registrant end @@ -117,9 +117,11 @@ class Ability end def static_registrant + customer_service can :manage, :registrant_domains can :manage, :registrant_whois can :manage, Depp::Domain + can :manage, Domain end def user diff --git a/app/models/account_activity.rb b/app/models/account_activity.rb index 84a9f9137..3a0e7dc30 100644 --- a/app/models/account_activity.rb +++ b/app/models/account_activity.rb @@ -6,6 +6,8 @@ class AccountActivity < ActiveRecord::Base belongs_to :bank_transaction belongs_to :invoice + attr_accessor :registrar + CREATE = 'create' RENEW = 'renew' ADD_CREDIT = 'add_credit' @@ -22,12 +24,13 @@ class AccountActivity < ActiveRecord::Base end def to_csv - attributes = %w(description activity_type created_at sum) + attributes = %w(registrar description activity_type created_at sum) CSV.generate(headers: true) do |csv| - csv << %w(description activity_type receipt_date sum) + csv << %w(registrar description activity_type receipt_date sum) all.each do |x| # rubocop:disable Rails/FindEach + x.registrar = Registrar.find(x.account_id).try(:code) csv << attributes.map { |attr| x.send(attr) } end end diff --git a/app/models/bank_transaction.rb b/app/models/bank_transaction.rb index 1a34965bf..daf6abc29 100644 --- a/app/models/bank_transaction.rb +++ b/app/models/bank_transaction.rb @@ -2,7 +2,6 @@ class BankTransaction < ActiveRecord::Base include Versions belongs_to :bank_statement has_one :account_activity - has_many :directo_records, as: :item, class_name: 'Directo'# Deprecated scope :unbinded, lambda { where('id NOT IN (SELECT bank_transaction_id FROM account_activities where bank_transaction_id IS NOT NULL)') diff --git a/app/models/blocked_domain.rb b/app/models/blocked_domain.rb index f5ca0371c..2e337dce4 100644 --- a/app/models/blocked_domain.rb +++ b/app/models/blocked_domain.rb @@ -1,7 +1,9 @@ class BlockedDomain < ActiveRecord::Base include Versions - before_save :generate_data - before_destroy :remove_data + before_save :generate_data + after_destroy :remove_data + + validates :name, domain_name: true, uniqueness: true class << self @@ -21,19 +23,14 @@ class BlockedDomain < ActiveRecord::Base def generate_data return if Domain.where(name: name).any? - @json = generate_json - @body = generate_body - update_whois_server + wr = Whois::Record.find_or_initialize_by(name: name) + wr.json = @json = generate_json # we need @json to bind to class + wr.body = generate_body + wr.save end alias_method :update_whois_record, :generate_data - def update_whois_server - wr = Whois::Record.find_or_initialize_by(name: name) - wr.body = @body - wr.json = @json - wr.save - end def generate_body template = Rails.root.join("app/views/for_models/whois_other.erb".freeze) @@ -48,8 +45,6 @@ class BlockedDomain < ActiveRecord::Base end def remove_data - return if Domain.where(name: name).any? - - Whois::Record.where(name: name).delete_all + UpdateWhoisRecordJob.enqueue name, 'blocked' end end diff --git a/app/models/business_registry_cache.rb b/app/models/business_registry_cache.rb new file mode 100644 index 000000000..f73a5cfe8 --- /dev/null +++ b/app/models/business_registry_cache.rb @@ -0,0 +1,83 @@ + +=begin +The portal for registrants has to offer an overview of the domains the user is related to directly or through an organisation. +Personal relation is defined by matching the personal identification code associated with a domain and the one acquired on +authentication using electronic ID. Association through a business organisation requires a query to business registry. + + * when user logs in the personal identification code is sent to business registry (using XML service) + * business registry returns the list of business registry codes the user is a board member of + * the list is cached for two days (configurable) + * during that time no new queries are made to business registry for that personal identification code + and the cached organisation code listing is used + * user sees the listing of domains that are associated with him/her directly or through registered organisation + * UI of the portal displays the list of organisation codes and names used to fetch additional domains for the user + (currently by clicking on a username in top right corner of the screen). + Also time and date of the query to the business registry is displayed with the list of organisations. + * if the query to the business registry fails for any reason the list of + domains associated directly with the user is still displayed with an error message indicating a problem + with receiving current list business entities. Outdated list of organisations cannot be used. +=end + +class BusinessRegistryCache < ActiveRecord::Base + + # 1. load domains by business + # 2. load domains by person + def associated_contacts + contact_ids = Contact.where(ident_type: 'org', ident: associated_businesses, ident_country_code: 'EE').pluck(:id) + contact_ids += Contact.where(ident_type: 'priv', ident: ident, ident_country_code: ident_country_code).pluck(:id) + contact_ids + end + + def associated_domain_ids + domain_ids = [] + + contact_ids = associated_contacts + + unless contact_ids.blank? + domain_ids = DomainContact.distinct.where(contact_id: contact_ids).pluck(:domain_id) + end + + domain_ids + end + + def associated_domains + Domain.includes(:registrar, :registrant).where(id: associated_domain_ids) + end + + class << self + def fetch_associated_domains(ident_code, ident_cc) + fetch_by_ident_and_cc(ident_code, ident_cc).associated_domains + end + + def fetch_by_ident_and_cc(ident_code, ident_cc) + cache = BusinessRegistryCache.where(ident: ident_code, ident_country_code: ident_cc).first_or_initialize + msg_start = "[Ariregister] #{ident_cc}-#{ident_code}:" + + # fetch new data if cache is expired + if cache.retrieved_on && cache.retrieved_on > (Time.zone.now - Setting.days_to_keep_business_registry_cache.days) + Rails.logger.info("#{msg_start} Info loaded from cache") + return cache + end + + cache.attributes = business_registry.associated_businesses(ident_code, ident_cc) + Rails.logger.info("#{msg_start} Info loaded from server") + + cache.save + cache + end + + def business_registry + Soap::Arireg.new + end + + def purge + STDOUT << "#{Time.zone.now.utc} - Starting Purge of old BusinessRegistry data from cache\n" unless Rails.env.test? + purged = 0 + BusinessRegistryCache.where('retrieved_on < ?', + Time.zone.now < Setting.days_to_keep_business_registry_cache.days).each do |br| + br.destroy and purged += 1 + end + STDOUT << "#{Time.zone.now.utc} - Finished purging #{purged} old BusinessRegistry cache items\n" unless Rails.env.test? + end + end +end diff --git a/app/models/contact.rb b/app/models/contact.rb index 99a41a6a4..3e7ae4fc8 100644 --- a/app/models/contact.rb +++ b/app/models/contact.rb @@ -12,6 +12,10 @@ class Contact < ActiveRecord::Base # TODO: remove later has_many :depricated_statuses, class_name: 'DepricatedContactStatus', dependent: :destroy + has_paper_trail class_name: "ContactVersion", meta: { children: :children_log } + + attr_accessor :legal_document_id + accepts_nested_attributes_for :legal_documents validates :name, :phone, :email, :ident, :ident_type, @@ -32,6 +36,7 @@ class Contact < ActiveRecord::Base validate :val_ident_valid_format? validate :uniq_statuses? validate :validate_html + validate :val_country_code after_initialize do self.statuses = [] if statuses.nil? @@ -39,7 +44,7 @@ class Contact < ActiveRecord::Base self.ident_updated_at = Time.zone.now if new_record? && ident_updated_at.blank? end - before_validation :set_ident_country_code + before_validation :to_upcase_country_code before_validation :prefix_code before_create :generate_auth_info @@ -330,22 +335,36 @@ class Contact < ActiveRecord::Base # TODO: refactor, it should not allow to destroy with normal destroy, # no need separate method # should use only in transaction - def destroy_and_clean + def destroy_and_clean frame if domains_present? errors.add(:domains, :exist) return false end + + legal_document_data = Epp::Domain.parse_legal_document_from_frame(frame) + + if legal_document_data + + doc = LegalDocument.create( + documentable_type: Contact, + document_type: legal_document_data[:type], + body: legal_document_data[:body] + ) + self.legal_documents = [doc] + self.legal_document_id = doc.id + self.save + end destroy end - def set_ident_country_code - return true unless ident_country_code_changed? && ident_country_code.present? - code = Country.new(ident_country_code) - if code - self.ident_country_code = code.alpha2 - else - errors.add(:ident, :invalid_country_code) - end + def to_upcase_country_code + self.ident_country_code = ident_country_code.upcase if ident_country_code + self.country_code = country_code.upcase if country_code + end + + def val_country_code + errors.add(:ident, :invalid_country_code) unless Country.new(ident_country_code) + errors.add(:ident, :invalid_country_code) unless Country.new(country_code) end def related_domain_descriptions @@ -415,7 +434,10 @@ class Contact < ActiveRecord::Base # fetch domains - domains = Domain.where("domains.id IN (#{filter_sql})").includes(:registrar).page(page).per(per) + domains = Domain.where("domains.id IN (#{filter_sql})") + domains = domains.where("domains.id" => params[:leave_domains]) if params[:leave_domains] + domains = domains.includes(:registrar).page(page).per(per) + if sorts.first == "registrar_name".freeze # using small rails hack to generate outer join domains = domains.includes(:registrar).where.not(registrars: {id: nil}).order("registrars.name #{order} NULLS LAST") @@ -434,6 +456,30 @@ class Contact < ActiveRecord::Base domains end + def all_registrant_domains(page: nil, per: nil, params: {}, registrant: nil) + + if registrant + sorts = params.fetch(:sort, {}).first || [] + sort = Domain.column_names.include?(sorts.first) ? sorts.first : "valid_to" + order = {"asc"=>"desc", "desc"=>"asc"}[sorts.second] || "desc" + + domain_ids = DomainContact.distinct.where(contact_id: registrant.id).pluck(:domain_id) + + domains = Domain.where(id: domain_ids).includes(:registrar).page(page).per(per) + if sorts.first == "registrar_name".freeze + domains = domains.includes(:registrar).where.not(registrars: {id: nil}).order("registrars.name #{order} NULLS LAST") + else + domains = domains.order("#{sort} #{order} NULLS LAST") + end + + domain_c = Hash.new([]) + registrant_domains.where(id: domains.map(&:id)).each{|d| domain_c[d.id] |= ["Registrant".freeze] } + DomainContact.where(contact_id: id, domain_id: domains.map(&:id)).each{|d| domain_c[d.domain_id] |= [d.type] } + domains.each{|d| d.roles = domain_c[d.id].uniq} + domains + end + end + def set_linked statuses << LINKED if statuses.detect { |s| s == LINKED }.blank? end @@ -498,8 +544,15 @@ class Contact < ActiveRecord::Base ]).present? end - def update_related_whois_records - related_domain_descriptions.each{ |x, y| WhoisRecord.find_by(name: x).try(:save) } - end + def update_related_whois_records + names = related_domain_descriptions.keys + UpdateWhoisRecordJob.enqueue(names, :domain) if names.present? + end + + def children_log + log = HashWithIndifferentAccess.new + log[:legal_documents]= [legal_document_id] + log + end end diff --git a/app/models/counter.rb b/app/models/counter.rb new file mode 100644 index 000000000..7d1c2b926 --- /dev/null +++ b/app/models/counter.rb @@ -0,0 +1,24 @@ +class Counter + def initialize value = 0 + @value = value + end + attr_accessor :value + def method_missing *args, &blk + @value.send(*args, &blk) + end + def to_s + @value.to_s + end + + def now + @value + end + + # pre-increment ".+" when x not present + def next(x = 1) + @value += x + end + def prev(x = 1) + @value -= x + end +end \ No newline at end of file diff --git a/app/models/directo.rb b/app/models/directo.rb index 5a719d0a7..05d9da5aa 100644 --- a/app/models/directo.rb +++ b/app/models/directo.rb @@ -1,15 +1,25 @@ class Directo < ActiveRecord::Base + DOMAIN_TO_PRODUCT = {"ee" => "01EE", "com.ee" => "02COM", "pri.ee" => "03PRI", "fie.ee"=>"04FIE", "med.ee" => "05MED"}.freeze belongs_to :item, polymorphic: true def self.send_receipts - new_trans = Invoice.where(invoice_type: "DEB", in_directo: false).where.not(cancelled_at: nil) + new_trans = Invoice.where(invoice_type: "DEB", in_directo: false).where(cancelled_at: nil) + total = new_trans.count + counter = 0 + Rails.logger.info("[DIRECTO] Will try to send #{total} invoices") + new_trans.find_in_batches(batch_size: 10).each do |group| mappers = {} # need them as no direct connection between invoice builder = Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml| xml.invoices { group.each do |invoice| - next if invoice.account_activity.nil? || invoice.account_activity.bank_transaction.nil? - # next if invoice.account_activity.bank_transaction.sum.nil? || invoice.account_activity.bank_transaction.sum != invoice.sum_cache + + if invoice.account_activity.nil? || invoice.account_activity.bank_transaction.nil? || + invoice.account_activity.bank_transaction.sum.nil? || invoice.account_activity.bank_transaction.sum != invoice.sum_cache + Rails.logger.info("[DIRECTO] Invoice #{invoice.number} has been skipped") + next + end + counter += 1 num = invoice.number mappers[num] = invoice @@ -36,14 +46,134 @@ class Directo < ActiveRecord::Base response = RestClient::Request.execute(url: ENV['directo_invoice_url'], method: :post, payload: {put: "1", what: "invoice", xmldata: data}, verify_ssl: false).to_s dump_result_to_db(mappers, response) end + + STDOUT << "#{Time.zone.now.utc} - Directo receipts sending finished. #{counter} of #{total} are sent\n" end def self.dump_result_to_db mappers, xml Nokogiri::XML(xml).css("Result").each do |res| obj = mappers[res.attributes["docid"].value.to_i] - obj.directo_records.create!(response: res.as_json.to_h) + obj.directo_records.create!(response: res.as_json.to_h, invoice_number: obj.number) obj.update_columns(in_directo: true) Rails.logger.info("[DIRECTO] Invoice #{res.attributes["docid"].value} was pushed and return is #{res.as_json.to_h.inspect}") end end + + + def self.send_monthly_invoices(debug: false) + @debug = debug + I18n.locale = :et + month = Time.now - 1.month + invoices_until = month.end_of_month + date_format = "%Y-%m-%d" + invoice_counter= Counter.new + + min_directo = Setting.directo_monthly_number_min.presence.try(:to_i) + max_directo = Setting.directo_monthly_number_max.presence.try(:to_i) + last_directo = [Setting.directo_monthly_number_last.presence.try(:to_i), min_directo].compact.max || 0 + if max_directo && max_directo <= last_directo + raise "Directo counter is out of period (max allowed number is smaller than last counter number)" + end + + directo_next = last_directo + Registrar.where.not(test_registrar: true).find_each do |registrar| + unless registrar.cash_account + Rails.logger.info("[DIRECTO] Monthly invoice for registrar #{registrar.id} has been skipped as it doesn't has cash_account") + next + end + counter = Counter.new(1) + items = {} + registrar_activities = AccountActivity.where(account_id: registrar.account_ids).where("created_at BETWEEN ? AND ?",month.beginning_of_month, month.end_of_month) + + # adding domains items + registrar_activities.where(activity_type: [AccountActivity::CREATE, AccountActivity::RENEW]).each do |activity| + pricelist = load_activity_pricelist(activity) + unless pricelist + Rails.logger.error("[DIRECTO] Skipping activity #{activity.id} as pricelist not found") + next + end + + pricelist.years_amount.times do |i| + year = i+1 + hash = { + "ProductID" => DOMAIN_TO_PRODUCT[pricelist.category], + "Unit" => "tk", + "ProductName" => ".#{pricelist.category} registreerimine: #{pricelist.years_amount} aasta", + "UnitPriceWoVAT" => pricelist.price_decimal/pricelist.years_amount + } + hash["StartDate"] = (activity.created_at + (year-1).year).end_of_month.strftime(date_format) if year > 1 + hash["EndDate"] = (activity.created_at + (year-1).year + 1).end_of_month.strftime(date_format) if year > 1 + + if items.has_key?(hash) + items[hash]["Quantity"] += 1 + else + items[hash] = {"RN"=>counter.next, "RR" => counter.now - i, "Quantity"=> 1} + end + end + end + + #adding prepaiments + if items.any? + total = 0 + items.each{ |key, val| total += val["Quantity"] * key["UnitPriceWoVAT"] } + hash = {"ProductID" => Setting.directo_receipt_product_name, "Unit" => "tk", "ProductName" => "Domeenide ettemaks", "UnitPriceWoVAT"=>total} + items[hash] = {"RN"=>counter.next, "RR" => counter.now, "Quantity"=> -1} + end + + # generating XML + if items.any? + directo_next += 1 + invoice_counter.next + + builder = Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml| + xml.invoices{ + xml.invoice("Number" =>directo_next, + "InvoiceDate" =>invoices_until.strftime(date_format), + "PaymentTerm" =>Setting.directo_receipt_payment_term, + "CustomerCode"=>registrar.directo_handle, + "Language" =>"", + "Currency" =>registrar_activities.first.currency, + "SalesAgent" =>Setting.directo_sales_agent){ + xml.line("RN" => 1, "RR"=>1, "ProductName"=> "Domeenide registreerimine - #{I18n.l(invoices_until, format: "%B %Y").titleize}") + items.each do |line, val| + xml.line(val.merge(line)) + end + } + } + end + + data = builder.to_xml.gsub("\n",'') + response = RestClient::Request.execute(url: ENV['directo_invoice_url'], method: :post, payload: {put: "1", what: "invoice", xmldata: data}, verify_ssl: false).to_s + if @debug + STDOUT << "#{Time.zone.now.utc} - Directo xml had to be sent #{data}\n" + else + Setting.directo_monthly_number_last = directo_next + Nokogiri::XML(response).css("Result").each do |res| + Directo.create!(request: data, response: res.as_json.to_h, invoice_number: directo_next) + Rails.logger.info("[DIRECTO] Invoice #{res.attributes["docid"].value} was pushed and return is #{res.as_json.to_h.inspect}") + end + end + else + Rails.logger.info("[DIRECTO] Registrar #{registrar.id} has nothing to be sent to Directo") + end + + end + STDOUT << "#{Time.zone.now.utc} - Directo invoices sending finished. #{invoice_counter.now} are sent\n" + end + + + def self.load_activity_pricelist activity + @pricelists ||= {} + return @pricelists[activity.log_pricelist_id] if @pricelists.has_key?(activity.log_pricelist_id) + + pricelist = Pricelist.find_by(id: activity.log_pricelist_id) || PricelistVersion.find_by(item_id: activity.log_pricelist_id).try(:reify) + unless pricelist + @pricelists[activity.log_pricelist_id] = nil + Rails.logger.info("[DIRECTO] AccountActivity #{activity.id} cannot be sent as pricelist wasn't found #{activity.log_pricelist_id}") + return + end + + @pricelists[activity.log_pricelist_id] = pricelist.version_at(activity.created_at) || pricelist + end end + diff --git a/app/models/domain.rb b/app/models/domain.rb index 9da57e27a..05804d02f 100644 --- a/app/models/domain.rb +++ b/app/models/domain.rb @@ -7,6 +7,8 @@ class Domain < ActiveRecord::Base attr_accessor :roles + attr_accessor :legal_document_id + # TODO: whois requests ip whitelist for full info for own domains and partial info for other domains # TODO: most inputs should be trimmed before validatation, probably some global logic? @@ -43,7 +45,7 @@ class Domain < ActiveRecord::Base has_many :dnskeys, dependent: :destroy has_many :keyrelays - has_one :whois_record, dependent: :destroy + has_one :whois_record # destroyment will be done in after_commit accepts_nested_attributes_for :dnskeys, allow_destroy: true @@ -87,14 +89,11 @@ class Domain < ActiveRecord::Base true end - after_save :update_whois_record + after_commit :update_whois_record after_create :update_reserved_domains def update_reserved_domains - return unless in_reserved_list? - rd = ReservedDomain.by_domain(name).first - rd.password = SecureRandom.hex - rd.save + ReservedDomain.new_password_for(name) if in_reserved_list? end validates :name_dirty, domain_name: true, uniqueness: true @@ -203,6 +202,31 @@ class Domain < ActiveRecord::Base statuses.include? DomainStatus::SERVER_TECH_CHANGE_PROHIBITED end + def self.clean_expired_pendings + ActiveSupport::Deprecation.instance.deprecation_warning(DomainCron, __method__) + DomainCron.send(__method__) + end + + def self.start_expire_period + ActiveSupport::Deprecation.instance.deprecation_warning(DomainCron, __method__) + DomainCron.send(__method__) + end + + def self.start_redemption_grace_period + ActiveSupport::Deprecation.instance.deprecation_warning(DomainCron, __method__) + DomainCron.send(__method__) + end + + def self.start_delete_period + ActiveSupport::Deprecation.instance.deprecation_warning(DomainCron, __method__) + DomainCron.send(__method__) + end + + def self.destroy_delete_candidates + ActiveSupport::Deprecation.instance.deprecation_warning(DomainCron, __method__) + DomainCron.send(__method__) + end + class << self def convert_period_to_time(period, unit) return (period.to_i / 365).years if unit == 'd' @@ -220,122 +244,6 @@ class Domain < ActiveRecord::Base { admin_contacts: :registrar } ) end - - # rubocop: disable Metrics/AbcSize - # rubocop: disable Metrics/CyclomaticComplexity - # rubocop: disable Metrics/PerceivedComplexity - def clean_expired_pendings - STDOUT << "#{Time.zone.now.utc} - Clean expired domain pendings\n" unless Rails.env.test? - - expire_at = Setting.expire_pending_confirmation.hours.ago - count = 0 - expired_pending_domains = Domain.where('registrant_verification_asked_at <= ?', expire_at) - expired_pending_domains.each do |domain| - unless domain.pending_update? || domain.pending_delete? || domain.pending_delete_confirmation? - msg = "#{Time.zone.now.utc} - ISSUE: DOMAIN #{domain.id}: #{domain.name} IS IN EXPIRED PENDING LIST, " \ - "but no pendingDelete/pendingUpdate state present!\n" - STDOUT << msg unless Rails.env.test? - next - end - count += 1 - if domain.pending_update? - domain.send_mail :pending_update_expired_notification_for_new_registrant - end - if domain.pending_delete? || domain.pending_delete_confirmation? - DomainMailer.pending_delete_expired_notification(domain.id, true).deliver - end - domain.clean_pendings_lowlevel - unless Rails.env.test? - STDOUT << "#{Time.zone.now.utc} Domain.clean_expired_pendings: ##{domain.id} (#{domain.name})\n" - end - end - STDOUT << "#{Time.zone.now.utc} - Successfully cancelled #{count} domain pendings\n" unless Rails.env.test? - count - end - # rubocop: enable Metrics/PerceivedComplexity - # rubocop: enable Metrics/AbcSize - # rubocop: enable Metrics/CyclomaticComplexity - - # rubocop: disable Metrics/LineLength - def start_expire_period - STDOUT << "#{Time.zone.now.utc} - Expiring domains\n" unless Rails.env.test? - - domains = Domain.where('valid_to <= ?', Time.zone.now) - domains.each do |domain| - next unless domain.expirable? - domain.set_graceful_expired - DomainMailer.expiration_reminder(domain.id).deliver_in(Setting.expiration_reminder_mail.to_i.days) - STDOUT << "#{Time.zone.now.utc} Domain.start_expire_period: ##{domain.id} (#{domain.name}) #{domain.changes}\n" unless Rails.env.test? - domain.save(validate: false) - end - - STDOUT << "#{Time.zone.now.utc} - Successfully expired #{domains.count} domains\n" unless Rails.env.test? - end - - def start_redemption_grace_period - STDOUT << "#{Time.zone.now.utc} - Setting server_hold to domains\n" unless Rails.env.test? - - d = Domain.where('outzone_at <= ?', Time.zone.now) - d.each do |domain| - next unless domain.server_holdable? - domain.statuses << DomainStatus::SERVER_HOLD - STDOUT << "#{Time.zone.now.utc} Domain.start_redemption_grace_period: ##{domain.id} (#{domain.name}) #{domain.changes}\n" unless Rails.env.test? - domain.save(validate: false) - end - - STDOUT << "#{Time.zone.now.utc} - Successfully set server_hold to #{d.count} domains\n" unless Rails.env.test? - end - - def start_delete_period - STDOUT << "#{Time.zone.now.utc} - Setting delete_candidate to domains\n" unless Rails.env.test? - - d = Domain.where('delete_at <= ?', Time.zone.now) - d.each do |domain| - next unless domain.delete_candidateable? - domain.statuses << DomainStatus::DELETE_CANDIDATE - STDOUT << "#{Time.zone.now.utc} Domain.start_delete_period: ##{domain.id} (#{domain.name}) #{domain.changes}\n" unless Rails.env.test? - domain.save(validate: false) - end - - return if Rails.env.test? - STDOUT << "#{Time.zone.now.utc} - Successfully set delete_candidate to #{d.count} domains\n" - end - - # rubocop:disable Rails/FindEach - # rubocop:disable Metrics/AbcSize - def destroy_delete_candidates - STDOUT << "#{Time.zone.now.utc} - Destroying domains\n" unless Rails.env.test? - - c = 0 - Domain.where("statuses @> '{deleteCandidate}'::varchar[]").each do |x| - WhoisRecord.where(domain_id: x.id).destroy_all - destroy_with_message x - STDOUT << "#{Time.zone.now.utc} Domain.destroy_delete_candidates: by deleteCandidate ##{x.id} (#{x.name})\n" unless Rails.env.test? - - c += 1 - end - - Domain.where('force_delete_at <= ?', Time.zone.now).each do |x| - WhoisRecord.where(domain_id: x.id).destroy_all - destroy_with_message x - STDOUT << "#{Time.zone.now.utc} Domain.destroy_delete_candidates: by force delete time ##{x.id} (#{x.name})\n" unless Rails.env.test? - c += 1 - end - - STDOUT << "#{Time.zone.now.utc} - Successfully destroyed #{c} domains\n" unless Rails.env.test? - end - # rubocop: enable Metrics/AbcSize - # rubocop:enable Rails/FindEach - # rubocop: enable Metrics/LineLength - def destroy_with_message(domain) - domain.destroy - bye_bye = domain.versions.last - domain.registrar.messages.create!( - body: "#{I18n.t(:domain_deleted)}: #{domain.name}", - attached_obj_id: bye_bye.id, - attached_obj_type: bye_bye.class.to_s # DomainVersion - ) - end end def name=(value) @@ -370,7 +278,7 @@ class Domain < ActiveRecord::Base end def in_reserved_list? - ReservedDomain.pw_for(name).present? + @in_reserved_list ||= ReservedDomain.by_domain(name).any? end def pending_transfer @@ -439,7 +347,8 @@ class Domain < ActiveRecord::Base end - # state change shouln't be + # state changes may be done low-level - no validation + # in this metod we still save PaperTrail log. def clean_pendings_lowlevel statuses.delete(DomainStatus::PENDING_DELETE_CONFIRMATION) statuses.delete(DomainStatus::PENDING_UPDATE) @@ -448,13 +357,23 @@ class Domain < ActiveRecord::Base status_notes[DomainStatus::PENDING_UPDATE] = '' status_notes[DomainStatus::PENDING_DELETE] = '' - update_columns( + hash = { registrant_verification_token: nil, registrant_verification_asked_at: nil, pending_json: {}, status_notes: status_notes, - statuses: statuses.presence || [DomainStatus::OK] - ) + statuses: statuses.presence || [DomainStatus::OK], + # need this column in order to update PaperTrail version properly + updated_at: Time.now.utc + } + + # PaperTrail + self.attributes = hash + record_update + clear_version_instance! + reset_transaction_id + + update_columns(hash) end def pending_update! @@ -478,6 +397,7 @@ class Domain < ActiveRecord::Base self.registrant_verification_token = token self.registrant_verification_asked_at = asked_at set_pending_update + touch_always_version pending_json['new_registrant_id'] = new_registrant_id pending_json['new_registrant_email'] = new_registrant_email pending_json['new_registrant_name'] = new_registrant_name @@ -543,19 +463,14 @@ class Domain < ActiveRecord::Base period_i ||= period unit ||= period_unit + # TODO: test if name.scan(/\.(.+)\z/).first.first is faster zone = name.split('.').drop(1).join('.') p = period_i / 365 if unit == 'd' p = period_i / 12 if unit == 'm' p = period_i if unit == 'y' - if p > 1 - p = "#{p}years" - else - p = "#{p}year" - end - - Pricelist.pricelist_for(zone, operation, p) + Pricelist.pricelist_for(zone, operation, "#{p}year".pluralize(p)) end ### VALIDATIONS ### @@ -592,7 +507,7 @@ class Domain < ActiveRecord::Base def name_in_wire_format res = '' - parts = name.split('.') + parts = name_puny.split('.') parts.each do |x| res += format('%02X', x.length) # length of label in hex res += x.each_byte.map { |b| format('%02X', b) }.join # label @@ -728,8 +643,12 @@ class Domain < ActiveRecord::Base case s when DomainStatus::PENDING_DELETE self.delete_at = nil - # Handle any other special remove cases? - # when DomainStatus::FORCE_DELETE unset_force_delete + when DomainStatus::SERVER_MANUAL_INZONE # removal causes server hold to set + self.outzone_at = Time.zone.now if self.force_delete_at.present? + when DomainStatus::DomainStatus::EXPIRED # removal causes server hold to set + self.outzone_at = self.valid_to + 15.day + when DomainStatus::DomainStatus::SERVER_HOLD # removal causes server hold to set + self.outzone_at = nil end end end @@ -820,13 +739,14 @@ class Domain < ActiveRecord::Base log[:admin_contacts] = admin_contact_ids log[:tech_contacts] = tech_contact_ids log[:nameservers] = nameserver_ids + log[:legal_documents]= [legal_document_id] log[:registrant] = [registrant_id] log[:domain_statuses] = domain_status_ids log end def update_whois_record - whois_record.blank? ? create_whois_record : whois_record.save + UpdateWhoisRecordJob.enqueue name, 'domain' end def status_notes_array=(notes) @@ -841,5 +761,19 @@ class Domain < ActiveRecord::Base DomainMailer.send(action, DomainMailModel.new(self).send(action)).deliver end + + def self.to_csv + CSV.generate do |csv| + csv << column_names + all.each do |domain| + csv << domain.attributes.values_at(*column_names) + end + end + end + + def self.pdf(html) + kit = PDFKit.new(html) + kit.to_pdf + end end # rubocop: enable Metrics/ClassLength diff --git a/app/models/domain_cron.rb b/app/models/domain_cron.rb new file mode 100644 index 000000000..6f04b92d5 --- /dev/null +++ b/app/models/domain_cron.rb @@ -0,0 +1,132 @@ +class DomainCron + + def self.clean_expired_pendings + STDOUT << "#{Time.zone.now.utc} - Clean expired domain pendings\n" unless Rails.env.test? + + expire_at = Setting.expire_pending_confirmation.hours.ago + count = 0 + expired_pending_domains = Domain.where('registrant_verification_asked_at <= ?', expire_at) + expired_pending_domains.each do |domain| + unless domain.pending_update? || domain.pending_delete? || domain.pending_delete_confirmation? + msg = "#{Time.zone.now.utc} - ISSUE: DOMAIN #{domain.id}: #{domain.name} IS IN EXPIRED PENDING LIST, " \ + "but no pendingDelete/pendingUpdate state present!\n" + STDOUT << msg unless Rails.env.test? + next + end + count += 1 + if domain.pending_update? + DomainMailer.pending_update_expired_notification_for_new_registrant(domain.id).deliver + end + if domain.pending_delete? || domain.pending_delete_confirmation? + DomainMailer.pending_delete_expired_notification(domain.id, true).deliver + end + domain.clean_pendings_lowlevel + unless Rails.env.test? + STDOUT << "#{Time.zone.now.utc} DomainCron.clean_expired_pendings: ##{domain.id} (#{domain.name})\n" + end + UpdateWhoisRecordJob.enqueue domain.name, 'domain' + end + STDOUT << "#{Time.zone.now.utc} - Successfully cancelled #{count} domain pendings\n" unless Rails.env.test? + count + end + + def self.start_expire_period + STDOUT << "#{Time.zone.now.utc} - Expiring domains\n" unless Rails.env.test? + + domains = Domain.where('valid_to <= ?', Time.zone.now) + marked = 0 + real = 0 + domains.each do |domain| + next unless domain.expirable? + real += 1 + domain.set_graceful_expired + STDOUT << "#{Time.zone.now.utc} DomainCron.start_expire_period: ##{domain.id} (#{domain.name}) #{domain.changes}\n" unless Rails.env.test? + domain.save(validate: false) and marked += 1 + end + + STDOUT << "#{Time.zone.now.utc} - Successfully expired #{marked} of #{real} domains\n" unless Rails.env.test? + end + + def self.start_redemption_grace_period + STDOUT << "#{Time.zone.now.utc} - Setting server_hold to domains\n" unless Rails.env.test? + + d = Domain.where('outzone_at <= ?', Time.zone.now) + marked = 0 + real = 0 + d.each do |domain| + next unless domain.server_holdable? + real += 1 + domain.statuses << DomainStatus::SERVER_HOLD + STDOUT << "#{Time.zone.now.utc} DomainCron.start_redemption_grace_period: ##{domain.id} (#{domain.name}) #{domain.changes}\n" unless Rails.env.test? + domain.save(validate: false) and marked += 1 + end + + STDOUT << "#{Time.zone.now.utc} - Successfully set server_hold to #{marked} of #{real} domains\n" unless Rails.env.test? + marked + end + + #doing nothing, deprecated + + def self.start_delete_period + # begin + # STDOUT << "#{Time.zone.now.utc} - Setting delete_candidate to domains\n" unless Rails.env.test? + # + # d = Domain.where('delete_at <= ?', Time.zone.now) + # marked = 0 + # real = 0 + # d.each do |domain| + # next unless domain.delete_candidateable? + # real += 1 + # domain.statuses << DomainStatus::DELETE_CANDIDATE + # STDOUT << "#{Time.zone.now.utc} DomainCron.start_delete_period: ##{domain.id} (#{domain.name})\n" unless Rails.env.test? + # ::PaperTrail.whodunnit = "cron - #{__method__}" + # domain.save(validate: false) and marked += 1 + # end + # ensure # the operator should see what was accomplished + # STDOUT << "#{Time.zone.now.utc} - Finished setting delete_candidate - #{marked} out of #{real} successfully set\n" unless Rails.env.test? + # end + # marked + end + + def self.destroy_delete_candidates + STDOUT << "#{Time.zone.now.utc} - Destroying domains\n" unless Rails.env.test? + + c = 0 + + Domain.where('delete_at <= ?', Time.zone.now).each do |x| + next unless x.delete_candidateable? + + x.statuses << DomainStatus::DELETE_CANDIDATE + + # If domain successfully saved, add it to delete schedule + if x.save(validate: false) + ::PaperTrail.whodunnit = "cron - #{__method__}" + DomainDeleteJob.enqueue(x.id, run_at: rand(((24*60) - (DateTime.now.hour * 60 + DateTime.now.minute))).minutes.from_now) + STDOUT << "#{Time.zone.now.utc} Domain.destroy_delete_candidates: job added by deleteCandidate status ##{x.id} (#{x.name})\n" unless Rails.env.test? + c += 1 + end + end + + Domain.where('force_delete_at <= ?', Time.zone.now).each do |x| + DomainDeleteJob.enqueue(x.id, run_at: rand(((24*60) - (DateTime.now.hour * 60 + DateTime.now.minute))).minutes.from_now) + STDOUT << "#{Time.zone.now.utc} DomainCron.destroy_delete_candidates: job added by force delete time ##{x.id} (#{x.name})\n" unless Rails.env.test? + c += 1 + end + + STDOUT << "#{Time.zone.now.utc} - Job destroy added for #{c} domains\n" unless Rails.env.test? + end + + # rubocop: enable Metrics/AbcSize + # rubocop:enable Rails/FindEach + # rubocop: enable Metrics/LineLength + def self.destroy_with_message(domain) + domain.destroy + bye_bye = domain.versions.last + domain.registrar.messages.create!( + body: "#{I18n.t(:domain_deleted)}: #{domain.name}", + attached_obj_id: bye_bye.id, + attached_obj_type: bye_bye.class.to_s # DomainVersion + ) + end + +end diff --git a/app/models/epp/contact.rb b/app/models/epp/contact.rb index be4dfeaf9..52fef7143 100644 --- a/app/models/epp/contact.rb +++ b/app/models/epp/contact.rb @@ -37,10 +37,7 @@ class Epp::Contact < Contact at[:country_code] = f.css('postalInfo addr cc').text if f.css('postalInfo addr cc').present? at[:auth_info] = f.css('authInfo pw').text if f.css('authInfo pw').present? - legal_frame = f.css('legalDocument').first - if legal_frame.present? - at[:legal_documents_attributes] = legal_document_attrs(legal_frame) - end + at.merge!(ident_attrs(f.css('ident').first)) if new_record at end @@ -104,6 +101,7 @@ class Epp::Contact < Contact res end + end delegate :ident_attr_valid?, to: :class @@ -152,8 +150,14 @@ class Epp::Contact < Contact at[:statuses] = statuses - statuses_attrs(frame.css('rem'), 'rem') + statuses_attrs(frame.css('add'), 'add') end - legal_frame = frame.css('legalDocument').first - at[:legal_documents_attributes] = self.class.legal_document_attrs(legal_frame) + # legal_frame = frame.css('legalDocument').first + # at[:legal_documents_attributes] = self.class.legal_document_attrs(legal_frame) + + if doc = attach_legal_document(Epp::Domain.parse_legal_document_from_frame(frame)) + frame.css("legalDocument").first.content = doc.path if doc && doc.persisted? + self.legal_document_id = doc.id + end + self.deliver_emails = true # turn on email delivery for epp @@ -175,6 +179,8 @@ class Epp::Contact < Contact else throw :epp_error, {code: '2306', msg: I18n.t(:ident_update_error)} end + else + throw :epp_error, {code: '2306', msg: I18n.t(:ident_update_error)} end end @@ -218,4 +224,29 @@ class Epp::Contact < Contact status_list end + + def attach_legal_document(legal_document_data) + return unless legal_document_data + + legal_documents.create( + document_type: legal_document_data[:type], + body: legal_document_data[:body] + ) + end + + def add_legal_file_to_new frame + legal_document_data = Epp::Domain.parse_legal_document_from_frame(frame) + return unless legal_document_data + + doc = LegalDocument.create( + documentable_type: Contact, + document_type: legal_document_data[:type], + body: legal_document_data[:body] + ) + self.legal_documents = [doc] + + frame.css("legalDocument").first.content = doc.path if doc && doc.persisted? + self.legal_document_id = doc.id + end + end diff --git a/app/models/epp/domain.rb b/app/models/epp/domain.rb index c1274c02b..fff048666 100644 --- a/app/models/epp/domain.rb +++ b/app/models/epp/domain.rb @@ -133,7 +133,8 @@ class Epp::Domain < Domain [:base, :ds_data_not_allowed], [:base, :key_data_not_allowed], [:period, :not_a_number], - [:period, :not_an_integer] + [:period, :not_an_integer], + [:registrant, :cannot_be_missing] ], '2308' => [ [:base, :domain_name_blocked, { value: { obj: 'name', val: name_dirty } }] @@ -155,7 +156,8 @@ class Epp::Domain < Domain def attrs_from(frame, current_user, action = nil) at = {}.with_indifferent_access - code = frame.css('registrant').first.try(:text) + registrant_frame = frame.css('registrant').first + code = registrant_frame.try(:text) if code.present? if action == 'chg' && registrant_change_prohibited? add_epp_error('2304', nil, DomainStatus::SERVER_REGISTRANT_CHANGE_PROHIBITED, I18n.t(:object_status_prohibits_operation)) @@ -166,7 +168,10 @@ class Epp::Domain < Domain else add_epp_error('2303', 'registrant', code, [:registrant, :not_found]) end - end + else + add_epp_error('2306', nil, nil, [:registrant, :cannot_be_missing]) + end if registrant_frame + at[:name] = frame.css('name').text if new_record? at[:registrar_id] = current_user.registrar.try(:id) @@ -195,9 +200,27 @@ class Epp::Domain < Domain end at[:dnskeys_attributes] = dnskeys_attrs(dnskey_frame, action) - at[:legal_documents_attributes] = legal_document_from(frame) + at end + + + # Adding legal doc to domain and + # if something goes wrong - raise Rollback error + def add_legal_file_to_new frame + legal_document_data = Epp::Domain.parse_legal_document_from_frame(frame) + return unless legal_document_data + + doc = LegalDocument.create( + documentable_type: Domain, + document_type: legal_document_data[:type], + body: legal_document_data[:body] + ) + self.legal_documents = [doc] + + frame.css("legalDocument").first.content = doc.path if doc && doc.persisted? + self.legal_document_id = doc.id + end # rubocop: enable Metrics/PerceivedComplexity # rubocop: enable Metrics/CyclomaticComplexity # rubocop: enable Metrics/MethodLength @@ -457,15 +480,6 @@ class Epp::Domain < Domain status_list end - def legal_document_from(frame) - ld = frame.css('legalDocument').first - return [] unless ld - - [{ - body: ld.text, - document_type: ld['type'] - }] - end # rubocop: disable Metrics/AbcSize # rubocop: disable Metrics/CyclomaticComplexity @@ -477,6 +491,7 @@ class Epp::Domain < Domain if doc = attach_legal_document(Epp::Domain.parse_legal_document_from_frame(frame)) frame.css("legalDocument").first.content = doc.path if doc && doc.persisted? + self.legal_document_id = doc.id end at_add = attrs_from(frame.css('add'), current_user, 'add') @@ -494,6 +509,15 @@ class Epp::Domain < Domain self.up_date = Time.zone.now end + if registrant_id && registrant.code == frame.css('registrant') + + throw :epp_error, { + code: '2305', + msg: I18n.t(:contact_already_associated_with_the_domain) + } + + end + if errors.empty? && verify && Setting.request_confrimation_on_registrant_change_enabled && frame.css('registrant').present? && @@ -867,6 +891,7 @@ class Epp::Domain < Domain ld = parsed_frame.css('legalDocument').first return nil unless ld return nil if ld.text.starts_with?(ENV['legal_documents_dir']) # escape reloading + return nil if ld.text.starts_with?('/home/') # escape reloading { body: ld.text, diff --git a/app/models/invoice.rb b/app/models/invoice.rb index 5c7dafe85..425202a4c 100644 --- a/app/models/invoice.rb +++ b/app/models/invoice.rb @@ -11,6 +11,18 @@ class Invoice < ActiveRecord::Base scope :unbinded, lambda { where('id NOT IN (SELECT invoice_id FROM account_activities where invoice_id IS NOT NULL)') } + scope :all_columns, ->{select("invoices.*")} + scope :sort_due_date_column, ->{all_columns.select("CASE WHEN invoices.cancelled_at is not null THEN + (invoices.cancelled_at + interval '100 year') ELSE + invoices.due_date END AS sort_due_date")} + scope :sort_by_sort_due_date_asc, ->{sort_due_date_column.order("sort_due_date ASC")} + scope :sort_by_sort_due_date_desc, ->{sort_due_date_column.order("sort_due_date DESC")} + scope :sort_receipt_date_column, ->{all_columns.includes(:account_activity).references(:account_activity).select(%Q{ + CASE WHEN account_activities.created_at is not null THEN account_activities.created_at + WHEN invoices.cancelled_at is not null THEN invoices.cancelled_at + interval '100 year' + ELSE NULL END AS sort_receipt_date })} + scope :sort_by_sort_receipt_date_asc, ->{sort_receipt_date_column.order("sort_receipt_date ASC")} + scope :sort_by_sort_receipt_date_desc, ->{sort_receipt_date_column.order("sort_receipt_date DESC")} attr_accessor :billing_email validates :billing_email, email_format: { message: :invalid }, allow_blank: true diff --git a/app/models/legal_document.rb b/app/models/legal_document.rb index 5aef34675..b4bf3c96b 100644 --- a/app/models/legal_document.rb +++ b/app/models/legal_document.rb @@ -1,4 +1,7 @@ class LegalDocument < ActiveRecord::Base + include EppErrors + MIN_BODY_SIZE = (1.37 * 3.kilobytes).ceil + if ENV['legal_document_types'].present? TYPES = ENV['legal_document_types'].split(',').map(&:strip) else @@ -9,9 +12,23 @@ class LegalDocument < ActiveRecord::Base belongs_to :documentable, polymorphic: true + + validate :val_body_length, if: ->(file){ file.path.blank? && !Rails.env.staging?} + before_create :add_creator before_save :save_to_filesystem + def epp_code_map + { + '2306' => [ + [:body, :length] + ] + } + end + + def val_body_length + errors.add(:body, :length) if body.nil? || body.size < MIN_BODY_SIZE + end def save_to_filesystem diff --git a/app/models/pricelist.rb b/app/models/pricelist.rb index 17420dfa1..d38e4290d 100644 --- a/app/models/pricelist.rb +++ b/app/models/pricelist.rb @@ -8,6 +8,8 @@ class Pricelist < ActiveRecord::Base ) } + scope :valid_at, ->(time){ where("valid_from IS NULL OR valid_from <= ?", time).where("valid_to IS NULL OR valid_to >= ?", time) } + monetize :price_cents validates :price_cents, :price_currency, :price, @@ -27,6 +29,14 @@ class Pricelist < ActiveRecord::Base "#{operation_category} #{category}" end + def years_amount + duration.to_i + end + + def price_decimal + price_cents / BigDecimal.new('100') + end + class << self def pricelist_for(zone, operation, period) lists = valid.where(category: zone, operation_category: operation, duration: period) diff --git a/app/models/registrant_user.rb b/app/models/registrant_user.rb index 9a69e8acb..12cae0d82 100644 --- a/app/models/registrant_user.rb +++ b/app/models/registrant_user.rb @@ -1,4 +1,5 @@ class RegistrantUser < User + ACCEPTED_ISSUER = 'AS Sertifitseerimiskeskus' attr_accessor :idc_data def ability @@ -6,6 +7,19 @@ class RegistrantUser < User end delegate :can?, :cannot?, to: :ability + def ident + registrant_ident.to_s.split("-").last + end + + def domains + ident_cc, ident = registrant_ident.to_s.split '-' + Domain.includes(:registrar, :registrant).where(contacts: { + ident_type: 'priv', + ident: ident, #identity_code, + ident_country_code: ident_cc #country_code + }) + end + def to_s username end @@ -13,15 +27,23 @@ class RegistrantUser < User class << self def find_or_create_by_idc_data(idc_data, issuer_organization) return false if idc_data.blank? - return false if issuer_organization != 'AS Sertifitseerimiskeskus' + return false if issuer_organization != ACCEPTED_ISSUER idc_data.force_encoding('UTF-8') - logger.error(idc_data) - logger.error(idc_data.encoding) - identity_code = idc_data.scan(/serialNumber=(\d+)/).flatten.first - country = idc_data.scan(/^\/C=(.{2})/).flatten.first - first_name = idc_data.scan(%r{/GN=(.+)/serialNumber}).flatten.first - last_name = idc_data.scan(%r{/SN=(.+)/GN}).flatten.first + + # handling here new and old mode + if idc_data.starts_with?("/") + identity_code = idc_data.scan(/serialNumber=(\d+)/).flatten.first + country = idc_data.scan(/^\/C=(.{2})/).flatten.first + first_name = idc_data.scan(%r{/GN=(.+)/serialNumber}).flatten.first + last_name = idc_data.scan(%r{/SN=(.+)/GN}).flatten.first + else + parse_str = "," + idc_data + identity_code = parse_str.scan(/,serialNumber=(\d+)/).flatten.first + country = parse_str.scan(/,C=(.{2})/).flatten.first + first_name = parse_str.scan(/,GN=([^,]+)/).flatten.first + last_name = parse_str.scan(/,SN=([^,]+)/).flatten.first + end u = where(registrant_ident: "#{country}-#{identity_code}").first_or_create u.username = "#{first_name} #{last_name}" diff --git a/app/models/reserved_domain.rb b/app/models/reserved_domain.rb index c5d0cf9f2..9f36fcebc 100644 --- a/app/models/reserved_domain.rb +++ b/app/models/reserved_domain.rb @@ -2,7 +2,11 @@ class ReservedDomain < ActiveRecord::Base include Versions # version/reserved_domain_version.rb before_save :fill_empty_passwords before_save :generate_data - before_destroy :remove_data + after_destroy :remove_data + + validates :name, domain_name: true, uniqueness: true + + class << self @@ -18,33 +22,40 @@ class ReservedDomain < ActiveRecord::Base def any_of_domains names where(name: names) end + + def new_password_for name + record = by_domain(name).first + return unless record + + record.regenerate_password + record.save + end end - def fill_empty_passwords - self.password = SecureRandom.hex unless self.password - end def name= val super SimpleIDN.to_unicode(val) end + def fill_empty_passwords + regenerate_password if self.password.blank? + end + + def regenerate_password + self.password = SecureRandom.hex + end + def generate_data return if Domain.where(name: name).any? - @json = generate_json - @body = generate_body - update_whois_server - end - - alias_method :update_whois_record, :generate_data - - def update_whois_server wr = Whois::Record.find_or_initialize_by(name: name) - wr.body = @body - wr.json = @json + wr.json = @json = generate_json # we need @json to bind to class + wr.body = generate_body wr.save end + alias_method :update_whois_record, :generate_data + def generate_body template = Rails.root.join("app/views/for_models/whois_other.erb".freeze) @@ -59,9 +70,7 @@ class ReservedDomain < ActiveRecord::Base end def remove_data - return if Domain.where(name: name).any? - - Whois::Record.where(name: name).delete_all + UpdateWhoisRecordJob.enqueue name, 'reserved' end end diff --git a/app/models/soap/arireg.rb b/app/models/soap/arireg.rb new file mode 100644 index 000000000..422a72dd9 --- /dev/null +++ b/app/models/soap/arireg.rb @@ -0,0 +1,219 @@ +# coding: utf-8 +require 'savon' +=begin + +Estonian Business registry provides information about registered companies via xml (SOAP over HTTPS). + +Note: + The SSL endpoint certificate is self signed. + +Documentation: + http://www.rik.ee/et/e-ariregister/xml-teenus + Specifications are in Eng and Est + User contract required + +Testing: + https://demo-ariregxml.rik.ee:447/testariport/?wsdl + http://demo-ariregxml.rik.ee:81 + https://demo-ariregxml.rik.ee:447 + +Live service: + https://ariregxml.rik.ee/ariport/?wsdl + https://ariregxml.rik.ee/ + +Implements Soap::Arireg # associated_businesses + 8. arireg.paringesindus_v4 + Rights of representation of all persons related to the company (newer) + http://www2.rik.ee/schemas/xtee/arireg/live/paringesindus_v4.xsd + expects personal id code, to fetch list of registered business id codes + returning {ident: person, ident_country_code: ... associated_businesses: [...id_codes...]} + +=end + +# do some SSL set up? +# ssl_version +# ssl_verify_mode +# ssl_cert_key_file +# ssl_cert_key +# ssl_cert_key_password +# ssl_cert_file +# ssl_cert +# ssl_ca_cert_file +# ssl_ca_cert + +module Soap + + class Arireg + + class NotAvailableError < StandardError + attr_accessor :json + def initialize(params) + params[:message] = "#{I18n.t(:business_registry_service_not_available)}" unless params.key? :message + @json = params + + super(params) + end + end + + class << self + attr_accessor :wsdl, :host, :username, :password + end + + def initialize + if self.class.username.nil? + if Rails.application.secrets.key?(:arireg) + arireg = Rails.application.secrets[:arireg].with_indifferent_access + self.class.username = arireg[:username] + self.class.password = arireg[:password] + if self.class.wsdl.nil? # no override of config/environments/* ? + self.class.wsdl = arireg[:wsdl] + self.class.host = arireg[:host] + end + else + self.class.username = ENV['arireg_username'] + self.class.password = ENV['arireg_password'] + end + end + if self.class.wsdl.nil? + self.class.wsdl = ENV['arireg_wsdl'] + self.class.host = ENV['arireg_host'] + end + + # note Savon has error if https w/non-standard port, + # use non-standard force to pre-set endpoint + @client = Savon.client(wsdl: self.class.wsdl, + host: self.class.host, + endpoint: "#{self.class.host}/cgi-bin/consumer_proxy") + @session = nil + end + + # retrieve business id codes for business that a person has a legal role + def associated_businesses(ident, ident_cc = 'EST') + begin + msg = { + 'fyysilise_isiku_kood' => ident, + 'fyysilise_isiku_koodi_riik' => country_code_3(ident_cc) + } + Rails.logger.info "[Ariregister] Request sent with data: #{msg.inspect}" + + response = @client.call :paringesindus_v4, message: body(msg) + content = extract response, :paringesindus_v4_response + Rails.logger.info "[Ariregister] Got response with data: #{content.inspect}" + + if content.present? && content[:ettevotjad].key?(:item) + business_ident = items(content, :ettevotjad).map{|item| item[:ariregistri_kood]} + else + business_ident = [] + end + + { + ident: ident, + ident_country_code: ident_cc, + # ident_type: 'priv', + retrieved_on: Time.now, + associated_businesses: business_ident + } + rescue Savon::SOAPFault => fault + Rails.logger.error "[Ariregister] #{fault} Äriregister arireg #{self.class.username} at #{self.class.host }" + raise NotAvailableError.new(exception: fault) + rescue HTTPI::SSLError => ssl_error + Rails.logger.error "[Ariregister] #{ssl_error} at #{self.class.host}" + raise NotAvailableError.new(exception: ssl_error) + rescue SocketError => sock + Rails.logger.error "[Ariregister] #{sock}" + raise NotAvailableError.new(exception: sock) + end + end + + def debug + @client.globals.log_level :debug + @client.globals.log true + @client.globals.pretty_print_xml true + @debug = true + @client + end + + private + + # add required elements to request + def body(args) + if @session.nil? + args['ariregister_kasutajanimi'] = self.class.username + args['ariregister_parool'] = self.class.password + else + args['ariregister_sessioon'] = @session + end + {keha: args} + end + + # TLA --- three letter acronym required not two letter acronym, transform + def country_code_3(code) + if code.length == 2 + code = CC2X3[code] + raise NotAvailableError.new(message: 'Unrecognized Country') if code.nil? + end + code + end + + def extract(response, element) + # response envelope body has again header/body under element; header is user and password returned + response.hash[:envelope][:body][element][:keha] + end + + def items(content, parent) + items = content[parent][:item] + items.is_a?(Array) ? items : [items] + end + + CC2X3 = {"AF"=>"AFG", "AX"=>"ALA", "AL"=>"ALB", "DZ"=>"DZA", "AS"=>"ASM", + "AD"=>"AND", "AO"=>"AGO", "AI"=>"AIA", "AQ"=>"ATA", "AG"=>"ATG", + "AR"=>"ARG", "AM"=>"ARM", "AW"=>"ABW", "AU"=>"AUS", "AT"=>"AUT", + "AZ"=>"AZE", "BS"=>"BHS", "BH"=>"BHR", "BD"=>"BGD", "BB"=>"BRB", + "BY"=>"BLR", "BE"=>"BEL", "BZ"=>"BLZ", "BJ"=>"BEN", "BM"=>"BMU", + "BT"=>"BTN", "BO"=>"BOL", "BQ"=>"BES", "BA"=>"BIH", "BW"=>"BWA", + "BV"=>"BVT", "BR"=>"BRA", "IO"=>"IOT", "BN"=>"BRN", "BG"=>"BGR", + "BF"=>"BFA", "BI"=>"BDI", "CV"=>"CPV", "KH"=>"KHM", "CM"=>"CMR", + "CA"=>"CAN", "KY"=>"CYM", "CF"=>"CAF", "TD"=>"TCD", "CL"=>"CHL", + "CN"=>"CHN", "CX"=>"CXR", "CC"=>"CCK", "CO"=>"COL", "KM"=>"COM", + "CD"=>"COD", "CG"=>"COG", "CK"=>"COK", "CR"=>"CRI", "CI"=>"CIV", + "HR"=>"HRV", "CU"=>"CUB", "CW"=>"CUW", "CY"=>"CYP", "CZ"=>"CZE", + "DK"=>"DNK", "DJ"=>"DJI", "DM"=>"DMA", "DO"=>"DOM", "EC"=>"ECU", + "EG"=>"EGY", "SV"=>"SLV", "GQ"=>"GNQ", "ER"=>"ERI", "EE"=>"EST", + "ET"=>"ETH", "FK"=>"FLK", "FO"=>"FRO", "FJ"=>"FJI", "FI"=>"FIN", + "FR"=>"FRA", "GF"=>"GUF", "PF"=>"PYF", "TF"=>"ATF", "GA"=>"GAB", + "GM"=>"GMB", "GE"=>"GEO", "DE"=>"DEU", "GH"=>"GHA", "GI"=>"GIB", + "GR"=>"GRC", "GL"=>"GRL", "GD"=>"GRD", "GP"=>"GLP", "GU"=>"GUM", + "GT"=>"GTM", "GG"=>"GGY", "GN"=>"GIN", "GW"=>"GNB", "GY"=>"GUY", + "HT"=>"HTI", "HM"=>"HMD", "VA"=>"VAT", "HN"=>"HND", "HK"=>"HKG", + "HU"=>"HUN", "IS"=>"ISL", "IN"=>"IND", "ID"=>"IDN", "IR"=>"IRN", + "IQ"=>"IRQ", "IE"=>"IRL", "IM"=>"IMN", "IL"=>"ISR", "IT"=>"ITA", + "JM"=>"JAM", "JP"=>"JPN", "JE"=>"JEY", "JO"=>"JOR", "KZ"=>"KAZ", + "KE"=>"KEN", "KI"=>"KIR", "KP"=>"PRK", "KR"=>"KOR", "KW"=>"KWT", + "KG"=>"KGZ", "LA"=>"LAO", "LV"=>"LVA", "LB"=>"LBN", "LS"=>"LSO", + "LR"=>"LBR", "LY"=>"LBY", "LI"=>"LIE", "LT"=>"LTU", "LU"=>"LUX", + "MO"=>"MAC", "MK"=>"MKD", "MG"=>"MDG", "MW"=>"MWI", "MY"=>"MYS", + "MV"=>"MDV", "ML"=>"MLI", "MT"=>"MLT", "MH"=>"MHL", "MQ"=>"MTQ", + "MR"=>"MRT", "MU"=>"MUS", "YT"=>"MYT", "MX"=>"MEX", "FM"=>"FSM", + "MD"=>"MDA", "MC"=>"MCO", "MN"=>"MNG", "ME"=>"MNE", "MS"=>"MSR", + "MA"=>"MAR", "MZ"=>"MOZ", "MM"=>"MMR", "NA"=>"NAM", "NR"=>"NRU", + "NP"=>"NPL", "NL"=>"NLD", "NC"=>"NCL", "NZ"=>"NZL", "NI"=>"NIC", + "NE"=>"NER", "NG"=>"NGA", "NU"=>"NIU", "NF"=>"NFK", "MP"=>"MNP", + "NO"=>"NOR", "OM"=>"OMN", "PK"=>"PAK", "PW"=>"PLW", "PS"=>"PSE", + "PA"=>"PAN", "PG"=>"PNG", "PY"=>"PRY", "PE"=>"PER", "PH"=>"PHL", + "PN"=>"PCN", "PL"=>"POL", "PT"=>"PRT", "PR"=>"PRI", "QA"=>"QAT", + "RE"=>"REU", "RO"=>"ROU", "RU"=>"RUS", "RW"=>"RWA", "BL"=>"BLM", + "SH"=>"SHN", "KN"=>"KNA", "LC"=>"LCA", "MF"=>"MAF", "PM"=>"SPM", + "VC"=>"VCT", "WS"=>"WSM", "SM"=>"SMR", "ST"=>"STP", "SA"=>"SAU", + "SN"=>"SEN", "RS"=>"SRB", "SC"=>"SYC", "SL"=>"SLE", "SG"=>"SGP", + "SX"=>"SXM", "SK"=>"SVK", "SI"=>"SVN", "SB"=>"SLB", "SO"=>"SOM", + "ZA"=>"ZAF", "GS"=>"SGS", "SS"=>"SSD", "ES"=>"ESP", "LK"=>"LKA", + "SD"=>"SDN", "SR"=>"SUR", "SJ"=>"SJM", "SZ"=>"SWZ", "SE"=>"SWE", + "CH"=>"CHE", "SY"=>"SYR", "TW"=>"TWN", "TJ"=>"TJK", "TZ"=>"TZA", + "TH"=>"THA", "TL"=>"TLS", "TG"=>"TGO", "TK"=>"TKL", "TO"=>"TON", + "TT"=>"TTO", "TN"=>"TUN", "TR"=>"TUR", "TM"=>"TKM", "TC"=>"TCA", + "TV"=>"TUV", "UG"=>"UGA", "UA"=>"UKR", "AE"=>"ARE", "GB"=>"GBR", + "UM"=>"UMI", "US"=>"USA", "UY"=>"URY", "UZ"=>"UZB", "VU"=>"VUT", + "VE"=>"VEN", "VN"=>"VNM", "VG"=>"VGB", "VI"=>"VIR", "WF"=>"WLF", + "EH"=>"ESH", "YE"=>"YEM", "ZM"=>"ZMB", "ZW"=>"ZWE"} + end +end diff --git a/app/views/admin/account_activities/index.haml b/app/views/admin/account_activities/index.haml index 80ebba2f6..e29f12f75 100644 --- a/app/views/admin/account_activities/index.haml +++ b/app/views/admin/account_activities/index.haml @@ -45,7 +45,7 @@ .col-md-3 .col-md-2 .col-md-4{class: 'text-right'} - = t(:starting_balance) + " #{@sum.to_a.map(&:sum).sum.to_f} EUR" + = t(:starting_balance) + " #{@sum.to_f} EUR" %hr @@ -66,10 +66,10 @@ %th{class: 'col-xs-2'} = sort_link(@q, 'sum') %tbody - -total = @sum.to_a.map(&:sum).sum.to_f + -total = @sum.to_f - @account_activities.each do |x| %tr - %td= link_to(x.account.registrar.try(:code), admin_registrar_path(x.account.registrar)) + %td= x.account.registrar && link_to(x.account.registrar.try(:code), admin_registrar_path(x.account.registrar)) %td= x.description.present? ? x.description : '-' %td= x.activity_type ? t(x.activity_type) : '' %td= l(x.created_at) diff --git a/app/views/admin/blocked_domains/_form.haml b/app/views/admin/blocked_domains/_form.haml new file mode 100644 index 000000000..996d52843 --- /dev/null +++ b/app/views/admin/blocked_domains/_form.haml @@ -0,0 +1,17 @@ += form_for([:admin, @domain], html: {class: 'form-horizontal'}) do |f| + = render 'shared/full_errors', object: @domain + + .row + .col-md-8 + .panel.panel-default + .panel-heading.clearfix + .pull-left= t(:general) + .panel-body + .form-group + .col-md-4.control-label + = f.label :name + .col-md-7 + = f.text_field(:name, class: 'form-control') + .row + .col-md-8.text-right + = button_tag(t(:save), class: 'btn btn-primary') diff --git a/app/views/admin/blocked_domains/edit.haml b/app/views/admin/blocked_domains/edit.haml new file mode 100644 index 000000000..51d77f0cc --- /dev/null +++ b/app/views/admin/blocked_domains/edit.haml @@ -0,0 +1,3 @@ += render 'shared/title', name: t(:edit_pw) + += render 'form' diff --git a/app/views/admin/blocked_domains/index.haml b/app/views/admin/blocked_domains/index.haml index bd5660193..5f6ac69d0 100644 --- a/app/views/admin/blocked_domains/index.haml +++ b/app/views/admin/blocked_domains/index.haml @@ -1,10 +1,68 @@ +- content_for :actions do + = link_to(t(:new), new_admin_blocked_domain_path, class: 'btn btn-primary') = render 'shared/title', name: t(:blocked_domains) -= form_tag([:admin, :blocked_domains]) do |f| - .row - .col-md-12 - = text_area_tag :blocked_domains, @blocked_domains, class: 'form-control', rows: 30 - %hr - .row - .col-md-12.text-right - %button.btn.btn-warning=t(:save) +.row + .col-md-12 + = search_form_for [:admin, @q], html: { style: 'margin-bottom: 0;', class: 'js-form', autocomplete: 'off' } do |f| + .row + .col-md-3 + .form-group + = f.label :name + = f.search_field :name_matches, value: params[:q][:name_matches], class: 'form-control', placeholder: t(:name) + .col-md-3 + .form-group + = f.label t(:created_at_from) + = f.search_field :created_at_gteq, value: params[:q][:created_at_gteq], class: 'form-control datepicker', placeholder: t(:created_at_from) + .col-md-3 + .form-group + = f.label t(:created_at_until) + = f.search_field :created_at_lteq, value: params[:q][:created_at_lteq], class: 'form-control datepicker', placeholder: t(:created_at_until) + .row + .col-md-3 + .form-group + = label_tag t(:results_per_page) + = text_field_tag :results_per_page, params[:results_per_page], class: 'form-control', placeholder: t(:results_per_page) + .col-md-3{style: 'padding-top: 25px;'} + %button.btn.btn-primary +   + %span.glyphicon.glyphicon-search +   + %button.btn.btn-default.js-reset-form + = t(:clear_fields) +%hr +.row + .col-md-12 + .table-responsive + %table.table.table-hover.table-bordered.table-condensed + %thead + %tr + %th{class: 'col-xs-2'} + = sort_link(@q, 'name') + %th{class: 'col-xs-2'} + = sort_link(@q, 'created_at', t(:created_at)) + %th{class: 'col-xs-2'} + = sort_link(@q, 'updated_at', t(:updated_at)) + %th{class: 'col-xs-1'} + = t(:actions) + %tbody + - @domains.each do |x| + %tr + %td= x.name + %td= l(x.created_at, format: :short) + %td= l(x.updated_at, format: :short) + %td + %div{class: 'text-center'} + = link_to(t(:delete), delete_admin_blocked_domain_path(id: x.id), + data: { confirm: t(:are_you_sure) }, class: 'btn btn-danger btn-xs') +.row + .col-md-6 + = paginate @domains + .col-md-6.text-right + .pagination + = t(:result_count, count: @domains.total_count) + +:coffee + $(".js-reset-form").on "click", (e) -> + e.preventDefault(); + window.location = "#{admin_blocked_domains_path}" diff --git a/app/views/admin/blocked_domains/new.haml b/app/views/admin/blocked_domains/new.haml new file mode 100644 index 000000000..4461eea40 --- /dev/null +++ b/app/views/admin/blocked_domains/new.haml @@ -0,0 +1,3 @@ += render 'shared/title', name: t(:add_blocked_domain) + += render 'form' diff --git a/app/views/admin/contacts/index.haml b/app/views/admin/contacts/index.haml index 715b87eb6..14bd3ae06 100644 --- a/app/views/admin/contacts/index.haml +++ b/app/views/admin/contacts/index.haml @@ -59,7 +59,13 @@ .form-group = label_tag t(:results_per_page) = text_field_tag :results_per_page, params[:results_per_page], class: 'form-control', placeholder: t(:results_per_page) - .col-md-3{style: 'padding-top: 25px;'} + .col-md-3 + .form-group + = label_tag :only_no_country_code, "Ident CC missing" + = check_box_tag :only_no_country_code, '1',params[:only_no_country_code].eql?('1'), style: 'width:auto;height:auto;float:right' + + .row + .col-md-3{style: 'padding-top: 25px;float:right;'} %button.btn.btn-primary   %span.glyphicon.glyphicon-search diff --git a/app/views/admin/epp_logs/index.haml b/app/views/admin/epp_logs/index.haml index fa2e64267..550a20014 100644 --- a/app/views/admin/epp_logs/index.haml +++ b/app/views/admin/epp_logs/index.haml @@ -29,11 +29,11 @@ .col-md-3 .form-group = f.label t(:created_after) - = f.search_field :created_at_gteq, class: 'form-control', placeholder: t(:created_after), autocomplete: 'off' + = f.search_field :created_at_gteq, value: params[:q][:created_at_gteq], class: 'form-control datepicker', placeholder: t(:created_after), autocomplete: 'off' .col-md-3 .form-group = f.label t(:created_before) - = f.search_field :created_at_lteq, class: 'form-control', placeholder: t(:created_before), autocomplete: 'off' + = f.search_field :created_at_lteq, value: params[:q][:created_at_lteq], class: 'form-control datepicker', placeholder: t(:created_before), autocomplete: 'off' .col-md-3{style: 'padding-top: 25px;'} %button.btn.btn-primary   diff --git a/app/views/admin/invoices/index.haml b/app/views/admin/invoices/index.haml index 75b6285a4..4b34dba94 100644 --- a/app/views/admin/invoices/index.haml +++ b/app/views/admin/invoices/index.haml @@ -8,13 +8,13 @@ %thead %tr %th{class: 'col-xs-3'} - = sort_link(@q, 'invoice') + = sort_link(@q, :number) %th{class: 'col-xs-3'} - = sort_link(@q, 'buyer') + = sort_link(@q, :buyer_name, "Buyer") %th{class: 'col-xs-3'} - = sort_link(@q, 'due_date') + = sort_link(@q, :sort_due_date, "Due date") %th{class: 'col-xs-3'} - = sort_link(@q, 'receipt_date') + = sort_link(@q, :sort_receipt_date, "Receipt date") %tbody - @invoices.each do |x| %tr diff --git a/app/views/admin/registrars/_form.haml b/app/views/admin/registrars/_form.haml index f00bf6a14..48cfc8066 100644 --- a/app/views/admin/registrars/_form.haml +++ b/app/views/admin/registrars/_form.haml @@ -82,6 +82,11 @@ = f.label :code .col-md-7 = f.text_field(:code, class: 'form-control', disabled: !f.object.new_record?) + .form-group + .col-md-4.control-label + = f.label :test_registrar + .col-md-7 + = f.check_box :test_registrar, class: 'form-control' %hr .row diff --git a/app/views/admin/registrars/index.haml b/app/views/admin/registrars/index.haml index 8ba45d205..4e1c78294 100644 --- a/app/views/admin/registrars/index.haml +++ b/app/views/admin/registrars/index.haml @@ -14,12 +14,15 @@ = sort_link(@q, 'reg_no', t(:reg_no)) %th{class: 'col-xs-4'} = t(:credit_balance) + %th{class: 'col-xs-4'} + = t(:test_registrar) %tbody - @registrars.each do |x| %tr %td= link_to(x, [:admin, x]) %td= x.reg_no %td= "#{x.balance}" + %td= "#{x.test_registrar}" .row .col-md-12 = paginate @registrars diff --git a/app/views/admin/registrars/show.haml b/app/views/admin/registrars/show.haml index 35938c0c6..c1c8ebf6c 100644 --- a/app/views/admin/registrars/show.haml +++ b/app/views/admin/registrars/show.haml @@ -2,6 +2,10 @@ = link_to(t(:edit), edit_admin_registrar_path(@registrar), class: 'btn btn-primary') = link_to(t(:delete), admin_registrar_path(@registrar), method: :delete, data: { confirm: t(:are_you_sure) }, class: 'btn btn-danger') +- content_for :page_name do + = @registrar.name + - if @registrar.test_registrar? + %span{style: "color: #c9302c;"} (test) = render 'shared/title', name: @registrar.name - if @registrar.errors.any? diff --git a/app/views/admin/repp_logs/index.haml b/app/views/admin/repp_logs/index.haml index 0d33c4a6b..49c74405b 100644 --- a/app/views/admin/repp_logs/index.haml +++ b/app/views/admin/repp_logs/index.haml @@ -29,11 +29,11 @@ .col-md-3 .form-group = f.label t(:created_after) - = f.search_field :created_at_gteq, class: 'form-control', placeholder: t(:created_after), autocomplete: 'off' + = f.search_field :created_at_gteq, value: params[:q][:created_at_gteq], class: 'form-control datepicker', placeholder: t(:created_after), autocomplete: 'off' .col-md-3 .form-group = f.label t(:created_before) - = f.search_field :created_at_lteq, class: 'form-control', placeholder: t(:created_before), autocomplete: 'off' + = f.search_field :created_at_lteq, value: params[:q][:created_at_lteq], class: 'form-control datepicker', placeholder: t(:created_before), autocomplete: 'off' .col-md-3{style: 'padding-top: 25px;'} %button.btn.btn-primary   diff --git a/app/views/admin/reserved_domains/_form.haml b/app/views/admin/reserved_domains/_form.haml new file mode 100644 index 000000000..ec7492659 --- /dev/null +++ b/app/views/admin/reserved_domains/_form.haml @@ -0,0 +1,22 @@ += form_for([:admin, @domain], html: {class: 'form-horizontal'}) do |f| + = render 'shared/full_errors', object: @domain + + .row + .col-md-8 + .panel.panel-default + .panel-heading.clearfix + .pull-left= t(:general) + .panel-body + .form-group + .col-md-4.control-label + = f.label :name + .col-md-7 + = f.text_field(:name, class: 'form-control', disabled: !f.object.new_record?) + .form-group + .col-md-4.control-label + = f.label :password + .col-md-7 + = f.text_field(:password, placeholder: t(:optional), class: 'form-control') + .row + .col-md-8.text-right + = button_tag(t(:save), class: 'btn btn-primary') diff --git a/app/views/admin/reserved_domains/edit.haml b/app/views/admin/reserved_domains/edit.haml new file mode 100644 index 000000000..51d77f0cc --- /dev/null +++ b/app/views/admin/reserved_domains/edit.haml @@ -0,0 +1,3 @@ += render 'shared/title', name: t(:edit_pw) + += render 'form' diff --git a/app/views/admin/reserved_domains/index.haml b/app/views/admin/reserved_domains/index.haml index 15840ff93..06825b624 100644 --- a/app/views/admin/reserved_domains/index.haml +++ b/app/views/admin/reserved_domains/index.haml @@ -1,14 +1,72 @@ - content_for :actions do - = link_to('#', class: 'btn btn-default', "data-container": "body", "data-title": t('list_format_is_in_yaml'), "data-content": "domain.ee: authinfopw
seconddomain.ee:
thirddomain.ee: authinfo3

#{t('if_auth_info_is_left_empty_it_will_be_auto_generated')}
#{t('each_domain_name_must_end_with_colon_sign')}", "data-placement": "left", "data-toggle": "popover", "data-html" => "true") do - %span.glyphicon.glyphicon-info-sign{"aria-hidden" => "true"} - + = link_to(t(:new), new_admin_reserved_domain_path, class: 'btn btn-primary') = render 'shared/title', name: t(:reserved_domains) -= form_tag([:admin, :reserved_domains]) do |f| - .row - .col-md-12 - = text_area_tag :reserved_domains, @reserved_domains, class: 'form-control', rows: 30 - %hr - .row - .col-md-12.text-right - %button.btn.btn-warning=t(:save) +.row + .col-md-12 + = search_form_for [:admin, @q], html: { style: 'margin-bottom: 0;', class: 'js-form', autocomplete: 'off' } do |f| + .row + .col-md-3 + .form-group + = f.label :name + = f.search_field :name_matches, value: params[:q][:name_matches], class: 'form-control', placeholder: t(:name) + .col-md-3 + .form-group + = f.label t(:created_at_from) + = f.search_field :created_at_gteq, value: params[:q][:created_at_gteq], class: 'form-control datepicker', placeholder: t(:created_at_from) + .col-md-3 + .form-group + = f.label t(:created_at_until) + = f.search_field :created_at_lteq, value: params[:q][:created_at_lteq], class: 'form-control datepicker', placeholder: t(:created_at_until) + .row + .col-md-3 + .form-group + = label_tag t(:results_per_page) + = text_field_tag :results_per_page, params[:results_per_page], class: 'form-control', placeholder: t(:results_per_page) + .col-md-3{style: 'padding-top: 25px;'} + %button.btn.btn-primary +   + %span.glyphicon.glyphicon-search +   + %button.btn.btn-default.js-reset-form + = t(:clear_fields) +%hr +.row + .col-md-12 + .table-responsive + %table.table.table-hover.table-bordered.table-condensed + %thead + %tr + %th{class: 'col-xs-2'} + = sort_link(@q, 'name') + %th{class: 'col-xs-2'} + = sort_link(@q, 'password') + %th{class: 'col-xs-2'} + = sort_link(@q, 'created_at', t(:created_at)) + %th{class: 'col-xs-2'} + = sort_link(@q, 'updated_at', t(:updated_at)) + %th{class: 'col-xs-2'} + = t(:actions) + %tbody + - @domains.each do |x| + %tr + %td= x.name + %td= x.password + %td= l(x.created_at, format: :short) + %td= l(x.updated_at, format: :short) + %td + = link_to(t(:edit_pw), edit_admin_reserved_domain_path(id: x.id), + class: 'btn btn-primary btn-xs') + = link_to(t(:delete), delete_admin_reserved_domain_path(id: x.id), + data: { confirm: t(:are_you_sure) }, class: 'btn btn-danger btn-xs') +.row + .col-md-6 + = paginate @domains + .col-md-6.text-right + .pagination + = t(:result_count, count: @domains.total_count) + +:coffee + $(".js-reset-form").on "click", (e) -> + e.preventDefault(); + window.location = "#{admin_reserved_domains_path}" diff --git a/app/views/admin/reserved_domains/new.haml b/app/views/admin/reserved_domains/new.haml new file mode 100644 index 000000000..cd6e189f9 --- /dev/null +++ b/app/views/admin/reserved_domains/new.haml @@ -0,0 +1,3 @@ += render 'shared/title', name: t(:add_reserved_domain) + += render 'form' diff --git a/app/views/admin/settings/index.haml b/app/views/admin/settings/index.haml index e09e48396..6c7e3d74c 100644 --- a/app/views/admin/settings/index.haml +++ b/app/views/admin/settings/index.haml @@ -51,6 +51,7 @@ = render 'setting_row', var: :transfer_wait_time = render 'setting_row', var: :ds_digest_type = render 'setting_row', var: :client_side_status_editing_enabled + = render 'setting_row', var: :days_to_keep_business_registry_cache = render 'setting_row', var: :api_ip_whitelist_enabled = render 'setting_row', var: :registrar_ip_whitelist_enabled = render 'setting_row', var: :request_confrimation_on_registrant_change_enabled @@ -68,6 +69,9 @@ %tbody = render 'setting_row', var: :invoice_number_min = render 'setting_row', var: :invoice_number_max + = render 'setting_row', var: :directo_monthly_number_min + = render 'setting_row', var: :directo_monthly_number_max + = render 'setting_row', var: :directo_monthly_number_last = render 'setting_row', var: :days_to_keep_invoices_active = render 'setting_row', var: :days_to_keep_overdue_invoices_active = render 'setting_row', var: :minimum_deposit diff --git a/app/views/layouts/admin/application.haml b/app/views/layouts/admin/application.haml index 6e3257740..53a73520c 100644 --- a/app/views/layouts/admin/application.haml +++ b/app/views/layouts/admin/application.haml @@ -55,7 +55,7 @@ %li= link_to t(:pricelists), admin_pricelists_path %li= link_to t(:bank_statements), admin_bank_statements_path %li= link_to t(:invoices), admin_invoices_path - %li= link_to t(:account_activities), admin_account_activities_path + %li= link_to t(:account_activities), admin_account_activities_path(created_after: 'today') %li.divider %li.dropdown-header= t(:system) %li= link_to t(:settings), admin_settings_path @@ -64,8 +64,8 @@ %li= link_to t(:reserved_domains), admin_reserved_domains_path %li= link_to t(:mail_templates), admin_mail_templates_path -# %li= link_to t(:domains_history), admin_domain_versions_path - %li= link_to t(:epp_logs), admin_epp_logs_path - %li= link_to t(:repp_logs), admin_repp_logs_path + %li= link_to t(:epp_logs), admin_epp_logs_path(created_after: 'today') + %li= link_to t(:repp_logs), admin_repp_logs_path(created_after: 'today') %li= link_to t(:que), '/admin/que' - if signed_in? diff --git a/app/views/registrant/contacts/partials/_address.haml b/app/views/registrant/contacts/partials/_address.haml new file mode 100644 index 000000000..9c0f548e3 --- /dev/null +++ b/app/views/registrant/contacts/partials/_address.haml @@ -0,0 +1,23 @@ +.panel.panel-default + .panel-heading + %h3.panel-title= t(:address) + .panel-body + %dl.dl-horizontal + - if @contact.org_name.present? + %dt= t(:org_name) + %dd= @contact.org_name + + %dt= t(:street) + %dd= @contact.street.to_s.gsub("\n", '
').html_safe + + %dt= t(:city) + %dd= @contact.city + + %dt= t(:zip) + %dd= @contact.zip + + %dt= t(:state) + %dd= @contact.state + + %dt= t(:country) + %dd= @contact.country diff --git a/app/views/registrant/contacts/partials/_domains.haml b/app/views/registrant/contacts/partials/_domains.haml new file mode 100644 index 000000000..eb893053d --- /dev/null +++ b/app/views/registrant/contacts/partials/_domains.haml @@ -0,0 +1,30 @@ +- domains = contact.all_domains(page: params[:domain_page], per: 20, params: params.merge(leave_domains: domain_ids)) +#contacts.panel.panel-default + .panel-heading + .pull-left + = t(:domains) + .pull-right + = form_tag request.path, method: :get do + = select_tag :domain_filter, options_for_select(%w(Registrant AdminDomainContact TechDomainContact), selected: params[:domain_filter]), + include_blank: true, class: 'form-control2 selectize2' + %button.btn.btn-primary + %span.glyphicon.glyphicon-search + .clearfix + + .table-responsive + %table.table.table-hover.table-bordered.table-condensed + %thead + %tr + %th{class: 'col-xs-3'}=custom_sort_link t(:domain_name), :name + %th{class: 'col-xs-3'}=custom_sort_link t(:registrar), :registrar_name + %th{class: 'col-xs-3'}=custom_sort_link t(:valid_to), :valid_to + %th{class: 'col-xs-3'}=custom_sort_link t(:roles), :roles + %tbody + - domains.each do |x| + %tr + %td= link_to(x.name, [:registrant, x]) + %td= link_to(x.registrar, [:registrant, x.registrar]) + %td= l(x.valid_to, format: :short) + %td= x.roles.join(", ") + += paginate domains, param_name: :domain_page \ No newline at end of file diff --git a/app/views/registrant/contacts/partials/_general.haml b/app/views/registrant/contacts/partials/_general.haml new file mode 100644 index 000000000..114988bcc --- /dev/null +++ b/app/views/registrant/contacts/partials/_general.haml @@ -0,0 +1,48 @@ +.panel.panel-default + .panel-heading + %h3.panel-title= t(:general) + .panel-body + %dl.dl-horizontal + %dt= t(:id) + %dd= @contact.code + + %dt= t(:name) + %dd= @contact.name + + %dt= t(:password) + %dd + = text_field_tag :auth_info, @contact.auth_info, readonly: true, class: 'partially-hidden' + + %br + + %dt= t(:ident) + %dd= ident_for(@contact) + + %dt= t(:email) + %dd= @contact.email + + %dt= t(:phone) + %dd= @contact.phone + + - if @contact.fax + %dt= t(:fax) + %dd= @contact.fax + + %br + + %dt= t(:created) + %dd + = l(@contact.created_at, format: :short) + by + = @contact.name + + %dt= t(:updated) + %dd + = l(@contact.updated_at, format: :short) + by + = @contact.name + + %dt= t(:registrar) + %dd + - if @contact.registrar.present? + = link_to(@contact.registrar, registrant_registrar_path(@contact.registrar)) diff --git a/app/views/registrant/contacts/partials/_search.haml b/app/views/registrant/contacts/partials/_search.haml new file mode 100644 index 000000000..4a723bf6b --- /dev/null +++ b/app/views/registrant/contacts/partials/_search.haml @@ -0,0 +1,6 @@ += search_form_for [:registrant, @q] do |f| + = f.search_field :name_cont + = f.submit do + %span.glyphicon.glyphicon-search + + diff --git a/app/views/registrant/contacts/partials/_statuses.haml b/app/views/registrant/contacts/partials/_statuses.haml new file mode 100644 index 000000000..c39075754 --- /dev/null +++ b/app/views/registrant/contacts/partials/_statuses.haml @@ -0,0 +1,21 @@ +- panel_class = contact.errors.messages[:statuses] ? 'panel-danger' : 'panel-default' +#contact_statuses.panel{class: panel_class} + .panel-heading.clearfix + = t(:statuses) + .table-responsive + %table.table.table-hover.table-bordered.table-condensed + %thead + %tr + %th{class: 'col-xs-6'}= t(:status) + %th{class: 'col-xs-6'}= t(:notes) + %tbody + - contact.statuses.each do |status| + %tr + %td= status + %td= contact.status_notes[status] + + - if contact.errors.messages[:statuses] + %tfoot + - @domain.errors.messages[:statuses].each do |s| + %tr + %td{colspan: 4}= s diff --git a/app/views/registrant/contacts/show.haml b/app/views/registrant/contacts/show.haml new file mode 100644 index 000000000..521a8d549 --- /dev/null +++ b/app/views/registrant/contacts/show.haml @@ -0,0 +1,11 @@ += render 'shared/title', name: @contact.name + +.row + .col-md-6= render 'registrant/contacts/partials/general' + .col-md-6= render 'registrant/contacts/partials/address' +.row + .col-md-12= render 'registrant/contacts/partials/statuses', contact: @contact +.row + .col-md-12= render 'registrant/contacts/partials/domains', contact: @contact + + diff --git a/app/views/registrant/domains/domain_verification_url.haml b/app/views/registrant/domains/domain_verification_url.haml new file mode 100644 index 000000000..f75091a2e --- /dev/null +++ b/app/views/registrant/domains/domain_verification_url.haml @@ -0,0 +1,13 @@ +- content_for :actions do + = render 'shared/title', name: @domain.name + +.row + .col-md-12 + .panel.panel-default + .panel-heading + %h3.panel-title= t(:personal_domain_verification_url) + .panel-body + .input-group.input-group-lg + %span#sizing-addon1.input-group-addon.glyphicon.glyphicon-link + %input.form-control{"aria-describedby" => "sizing-addon1", type: "text", value: @verification_url} + diff --git a/app/views/registrant/domains/download_list.haml b/app/views/registrant/domains/download_list.haml new file mode 100644 index 000000000..40212812c --- /dev/null +++ b/app/views/registrant/domains/download_list.haml @@ -0,0 +1,28 @@ +!!! +%html + %head + %meta{:content => "text/html; charset=utf-8", "http-equiv" => "Content-Type"} + %title Contacts + %body + .col-md-12 + .table-responsive + %table.table.table-hover.table-bordered.table-condensed + %thead + %tr + %th{class: 'col-xs-2'} + =t(:name) + %th{class: 'col-xs-2'} + =t(:registrant) + %th{class: 'col-xs-2'} + =t(:valid_to) + %th{class: 'col-xs-2'} + =t(:registrar) + %tbody + - @domains.result.each do |x| + %tr + %td= x.name + %td= x.registrant + %td= l(x.valid_to, format: :short) + %td= x.registrar + .row + .col-md-6 diff --git a/app/views/registrant/domains/index.haml b/app/views/registrant/domains/index.haml index 8b71cefca..ca31d127d 100644 --- a/app/views/registrant/domains/index.haml +++ b/app/views/registrant/domains/index.haml @@ -1,5 +1,52 @@ = render 'shared/title', name: t(:domains) +.row + .col-md-12 + = search_form_for [:registrant, @q], html: { style: 'margin-bottom: 0;', class: 'js-form', autocomplete: 'off' } do |f| + .row + .col-md-3 + .form-group + = f.label :name + = f.search_field :name_matches, value: params[:q][:name_matches], class: 'form-control', placeholder: t(:name) + .col-md-3 + .form-group + = f.label t(:registrant_ident) + = f.search_field :registrant_ident_eq, class: 'form-control', placeholder: t(:registrant_ident) + .row + .col-md-3 + .form-group + = f.label t(:valid_to_from) + = f.search_field :valid_to_gteq, value: params[:q][:valid_to_gteq], class: 'form-control datepicker', placeholder: t(:valid_to_from) + .col-md-3 + .form-group + = f.label t(:valid_to_until) + = f.search_field :valid_to_lteq, value: params[:q][:valid_to_lteq], class: 'form-control datepicker', placeholder: t(:valid_to_until) + .col-md-3 + .form-group + = label_tag t(:results_per_page) + = text_field_tag :results_per_page, params[:results_per_page], class: 'form-control', placeholder: t(:results_per_page) + .col-md-3{style: 'padding-top: 25px;'} + %button.btn.btn-primary +   + %span.glyphicon.glyphicon-search +   + %button.btn.btn-default.js-reset-form + = t(:clear_fields) + .row + .col-md-3 + .btn-group{:role => "group"} + %button.btn.btn-default.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-toggle" => "dropdown", :type => "button"} + Download + %span.caret + %ul.dropdown-menu + %li= link_to 'PDF', download_list_registrant_domains_path(q: params[:q], format: "pdf") + %li= link_to 'CSV', download_list_registrant_domains_path(q: params[:q], format: "csv") + .col-md-3 + .col-md-3 + .col-md-3 + + + %hr .row .col-md-12 @@ -8,20 +55,30 @@ %thead %tr %th{class: 'col-xs-2'} - = t(:name) + = sort_link(@q, 'name') %th{class: 'col-xs-2'} - = t(:registrant) + = sort_link(@q, 'registrant_name', t(:registrant)) %th{class: 'col-xs-2'} - = t(:valid_to) + = sort_link(@q, 'valid_to', t(:valid_to)) %th{class: 'col-xs-2'} - = t(:registrar) + = sort_link(@q, 'registrar_name', t(:registrar)) %tbody - -# - @domains.each do |x| - -# %tr - -# %td= link_to(x, admin_domain_path(x)) - -# %td - -# - if x.registrant - -# = link_to(x.registrant, [:admin, x.registrant]) + - @domains.each do |x| + %tr + %td= link_to(x, registrant_domain_path(x)) + %td= link_to(x.registrant.name, registrant_contact_path(x.registrant)) if x.registrant + %td= l(x.valid_to, format: :short) + %td= link_to(x.registrar, registrant_registrar_path(x.registrar)) if x.registrar + + .row + .col-md-6 + = paginate @domains + .col-md-6.text-right + .pagination + = t(:result_count, count: @domains.total_count) + +:coffee + $(".js-reset-form").on "click", (e) -> + e.preventDefault(); + window.location = "#{registrant_domains_path}" - -# %td= l(x.valid_to, format: :short) - -# %td= link_to(x.registrar, admin_registrar_path(x.registrar)) if x.registrar diff --git a/app/views/registrant/domains/partials/_admin_contacts.haml b/app/views/registrant/domains/partials/_admin_contacts.haml new file mode 100644 index 000000000..5e49d3fbc --- /dev/null +++ b/app/views/registrant/domains/partials/_admin_contacts.haml @@ -0,0 +1,22 @@ +- panel_class = @domain.errors.messages[:admin_contacts] ? 'panel-danger' : 'panel-default' +.panel{class: panel_class} + .panel-heading.clearfix + = t(:admin_contacts) + .table-responsive + %table.table.table-hover.table-bordered.table-condensed + %thead + %tr + %th{class: 'col-xs-4'}= t(:name) + %th{class: 'col-xs-4'}= t(:id) + %th{class: 'col-xs-4'}= t(:email) + %tbody + - @domain.admin_contacts.each do |ac| + %tr + %td= link_to(ac, registrant_contact_path(ac)) + %td= ac.code + %td= ac.email + - if @domain.errors.messages[:admin_contacts] + %tfoot + - @domain.errors.messages[:admin_contacts].each do |x| + %tr + %td{colspan: 4}= x diff --git a/app/views/registrant/domains/partials/_dnskeys.haml b/app/views/registrant/domains/partials/_dnskeys.haml new file mode 100644 index 000000000..6d5759e65 --- /dev/null +++ b/app/views/registrant/domains/partials/_dnskeys.haml @@ -0,0 +1,25 @@ +- panel_class = @domain.errors.messages[:dnskeys] ? 'panel-danger' : 'panel-default' +#dnskeys.panel{class: panel_class} + .panel-heading.clearfix + = t(:dnskeys) + .table-responsive + %table.table.table-hover.table-bordered.table-condensed + %thead + %tr + %th{class: 'col-xs-1'}= t(:flag) + %th{class: 'col-xs-1'}= t(:protocol) + %th{class: 'col-xs-1'}= t(:algorithm) + %th{class: 'col-xs-9'}= t(:public_key) + %tbody + - @domain.dnskeys.each do |x| + %tr + %td= x.flags + %td= x.protocol + %td= x.alg + %td= x.public_key + - if @domain.errors.messages[:dnskeys] + %tfoot + - @domain.errors.messages[:dnskeys].each do |x| + %tr + %td{colspan: 4}= x + diff --git a/app/views/registrant/domains/partials/_general.haml b/app/views/registrant/domains/partials/_general.haml new file mode 100644 index 000000000..d80c1ce6a --- /dev/null +++ b/app/views/registrant/domains/partials/_general.haml @@ -0,0 +1,32 @@ +.panel.panel-default + .panel-heading + %h3.panel-title= t(:general) + .panel-body + %dl.dl-horizontal + %dt= t(:name) + %dd= @domain.name + + %dt= t(:registered_at) + %dd= l(@domain.registered_at) + + %dt= t(:registrar) + %dd= link_to(@domain.registrar, registrant_registrar_path(@domain.registrar)) + + %dt= t(:authinfo_pw) + %dd + = text_field_tag :password, @domain.auth_info, readonly: true, class: 'partially-hidden' + + %dt= t(:valid_from) + %dd= l(@domain.valid_from) + + %dt= t(:valid_to) + %dd= l(@domain.valid_to) + + %dt= t(:outzone_at) + %dd= l(@domain.outzone_at) + + %dt= t(:delete_at) + %dd= l(@domain.delete_at) + + %dt= t(:force_delete_at) + %dd= l(@domain.force_delete_at) diff --git a/app/views/registrant/domains/partials/_keyrelays.haml b/app/views/registrant/domains/partials/_keyrelays.haml new file mode 100644 index 000000000..d2d39f6ba --- /dev/null +++ b/app/views/registrant/domains/partials/_keyrelays.haml @@ -0,0 +1,20 @@ +.panel{class: 'panel-default'} + .panel-heading.clearfix + = t(:keyrelays) + .table-responsive + %table.table.table-hover.table-bordered.table-condensed + %thead + %tr + %th{class: 'col-xs-4'}= t(:uploaded_at) + %th{class: 'col-xs-3'}= t(:expiry) + %th{class: 'col-xs-2'}= t(:requester) + %th{class: 'col-xs-2'}= t(:accepter) + %th{class: 'col-xs-1'}= t(:status) + %tbody + - @domain.keyrelays.includes([:requester, :accepter]).order(pa_date: :desc).each do |x| + %tr + %td= link_to(x.pa_date, [:registrar, x]) + %td= x.expiry + %td= link_to(x.requester, [:registrar, x.requester]) + %td= link_to(x.accepter, [:registrar, x.accepter]) + %td= x.status diff --git a/app/views/registrant/domains/partials/_legal_documents.haml b/app/views/registrant/domains/partials/_legal_documents.haml new file mode 100644 index 000000000..7d740977b --- /dev/null +++ b/app/views/registrant/domains/partials/_legal_documents.haml @@ -0,0 +1,14 @@ +.panel.panel-default + .panel-heading.clearfix + = t(:legal_documents) + .table-responsive + %table.table.table-hover.table-bordered.table-condensed + %thead + %tr + %th{class: 'col-xs-8'}= t(:created_at) + %th{class: 'col-xs-4'}= t(:type) + %tbody + - legal_documents.each do |x| + %tr + %td= link_to(x.created_at, [:registrar, x]) + %td= x.document_type diff --git a/app/views/registrant/domains/partials/_nameservers.haml b/app/views/registrant/domains/partials/_nameservers.haml new file mode 100644 index 000000000..db3ca759a --- /dev/null +++ b/app/views/registrant/domains/partials/_nameservers.haml @@ -0,0 +1,23 @@ +- panel_class = @domain.errors.messages[:nameservers] ? 'panel-danger' : 'panel-default' +#nameservers.panel{class: panel_class} + .panel-heading.clearfix + = t(:nameservers) + .table-responsive + %table.table.table-hover.table-bordered.table-condensed + %thead + %tr + %th{class: 'col-xs-4'}= t(:hostname) + %th{class: 'col-xs-4'}= t(:ipv4) + %th{class: 'col-xs-4'}= t(:ipv6) + %tbody + - @domain.nameservers.each do |x| + %tr + %td= x + %td= x.ipv4 + %td= x.ipv6 + - if @domain.errors.messages[:nameservers] + %tfoot + - @domain.errors.messages[:nameservers].each do |x| + %tr + %td{colspan: 3}= x + diff --git a/app/views/registrant/domains/partials/_owner.haml b/app/views/registrant/domains/partials/_owner.haml new file mode 100644 index 000000000..812b97924 --- /dev/null +++ b/app/views/registrant/domains/partials/_owner.haml @@ -0,0 +1,19 @@ +.panel.panel-default + .panel-heading + %h3.panel-title= t(:registrant) + .panel-body + %dl.dl-horizontal + %dt= t(:name) + %dd= link_to(@domain.registrant.name, registrant_contact_path(@domain.registrant)) + + %dt= t(:id) + %dd= @domain.registrant_code + + %dt= t(:identity_code) + %dd= @domain.registrant_ident + + %dt= t(:email) + %dd= @domain.registrant_email + + %dt= t(:phone) + %dd= @domain.registrant_phone diff --git a/app/views/registrant/domains/partials/_statuses.haml b/app/views/registrant/domains/partials/_statuses.haml new file mode 100644 index 000000000..90a969324 --- /dev/null +++ b/app/views/registrant/domains/partials/_statuses.haml @@ -0,0 +1,18 @@ +#domain_statuses.panel.panel-default + .panel-heading.clearfix + = t(:statuses) + .table-responsive + %table.table.table-hover.table-bordered.table-condensed + %thead + %tr + %th{class: 'col-xs-6'}= t(:status) + %th{class: 'col-xs-6'}= t(:notes) + %tbody + - @domain.statuses.each do |status| + %tr + %td + - if [DomainStatus::PENDING_UPDATE, DomainStatus::PENDING_DELETE_CONFIRMATION].include?(status) && @domain.pending_json.present? + = link_to(status, domain_verification_url_registrant_domain_url(@domain.id)) + - else + = status + %td= @domain.status_notes[status] diff --git a/app/views/registrant/domains/partials/_tech_contacts.haml b/app/views/registrant/domains/partials/_tech_contacts.haml new file mode 100644 index 000000000..12844a41e --- /dev/null +++ b/app/views/registrant/domains/partials/_tech_contacts.haml @@ -0,0 +1,22 @@ +- panel_class = @domain.errors.messages[:tech_contacts] ? 'panel-danger' : 'panel-default' +#tech_contacts.panel{class: panel_class} + .panel-heading.clearfix + = t(:tech_contacts) + .table-responsive + %table.table.table-hover.table-bordered.table-condensed + %thead + %tr + %th{class: 'col-xs-4'}= t(:name) + %th{class: 'col-xs-4'}= t(:id) + %th{class: 'col-xs-4'}= t(:email) + %tbody + - @domain.tech_contacts.each do |tc| + %tr + %td= link_to(tc, registrant_contact_path(tc)) + %td= tc.code + %td= tc.email + - if @domain.errors.messages[:tech_contacts] + %tfoot + - @domain.errors.messages[:tech_contacts].each do |x| + %tr + %td{colspan: 4}= x diff --git a/app/views/registrant/domains/show.haml b/app/views/registrant/domains/show.haml new file mode 100644 index 000000000..4d524b785 --- /dev/null +++ b/app/views/registrant/domains/show.haml @@ -0,0 +1,17 @@ += render 'shared/title', name: @domain.name + +.row + .col-md-6= render 'registrant/domains/partials/general' + .col-md-6= render 'registrant/domains/partials/owner' +.row + .col-md-12= render 'registrant/domains/partials/tech_contacts' +.row + .col-md-12= render 'registrant/domains/partials/admin_contacts' +.row + .col-md-12= render 'registrant/domains/partials/statuses' +.row + .col-md-12= render 'registrant/domains/partials/nameservers' +.row + .col-md-12= render 'registrant/domains/partials/dnskeys' +.row + .col-md-12= render 'registrant/domains/partials/keyrelays' diff --git a/app/views/registrant/registrars/index.haml b/app/views/registrant/registrars/index.haml new file mode 100644 index 000000000..0489bcf52 --- /dev/null +++ b/app/views/registrant/registrars/index.haml @@ -0,0 +1,21 @@ +- content_for :actions do + = render 'shared/title', name: t(:registrars) + +.row + .col-md-12 + .table-responsive + %table.table.table-hover.table-bordered.table-condensed + %thead + %tr + %th{class: 'col-xs-6'} + = sort_link(@q, 'name') + %th{class: 'col-xs-6'} + = sort_link(@q, 'reg_no', t(:reg_no)) + %tbody + - @registrars.each do |x| + %tr + %td= link_to(x, [:registrar, x]) + %td= x.reg_no +.row + .col-md-12 + = paginate @registrars diff --git a/app/views/registrant/registrars/show.haml b/app/views/registrant/registrars/show.haml new file mode 100644 index 000000000..ed5c72b29 --- /dev/null +++ b/app/views/registrant/registrars/show.haml @@ -0,0 +1,53 @@ += render 'shared/title', name: @registrar.name + +- if @registrar.errors.any? + - @registrar.errors.each do |attr, err| + = err + %br +- if @registrar.errors.any? + %hr +.row + .col-md-6 + .panel.panel-default + .panel-heading + %h3.panel-title= t(:general) + .panel-body + %dl.dl-horizontal + %dt= t(:name) + %dd= @registrar.name + + %dt= t(:reg_no) + %dd= @registrar.reg_no + + %dt= t(:vat_no) + %dd= @registrar.vat_no + + %dt= t(:reference_no) + %dd= @registrar.reference_no + + %dt= t(:id) + %dd= @registrar.code + + .col-md-6 + .panel.panel-default + .panel-heading + %h3.panel-title= t(:contact) + .panel-body + %dl.dl-horizontal + %dt= t(:country) + %dd= @registrar.country + + %dt= t(:address) + %dd= @registrar.address + + %dt= t(:contact_phone) + %dd= @registrar.phone + + %dt= t(:contact_email) + %dd= @registrar.email + + %dt= t(:billing_address) + %dd= @registrar.billing_address + + %dt= t(:billing_email) + %dd= @registrar.billing_email diff --git a/app/views/registrant/whois/index.haml b/app/views/registrant/whois/index.haml index 3e390eaf3..3d95af638 100644 --- a/app/views/registrant/whois/index.haml +++ b/app/views/registrant/whois/index.haml @@ -17,5 +17,5 @@ %span.glyphicon.glyphicon-search   %hr - - if @results - = @results + - if @domain + %pre= @domain.body \ No newline at end of file diff --git a/app/views/registrar/contacts/form_partials/_legal_document.haml b/app/views/registrar/contacts/form_partials/_legal_document.haml index 7875e99c8..bffa69831 100644 --- a/app/views/registrar/contacts/form_partials/_legal_document.haml +++ b/app/views/registrar/contacts/form_partials/_legal_document.haml @@ -10,4 +10,4 @@ = f.label :legal_document, t(:legal_document) %p.help-block= t(:legal_document_max_size) .col-md-7 - = f.file_field :legal_document, :value => '' + = f.file_field :legal_document, :value => '', data: {legal_document: true} diff --git a/app/views/registrar/domains/_form.haml b/app/views/registrar/domains/_form.haml index 79771b118..83ad8add0 100644 --- a/app/views/registrar/domains/_form.haml +++ b/app/views/registrar/domains/_form.haml @@ -18,7 +18,7 @@ = label_tag 'domain[legal_document]', t(:legal_document), class: c %p.help-block= t(:legal_document_max_size) .col-md-7 - = file_field_tag 'domain[legal_document]', required: fr + = file_field_tag 'domain[legal_document]', required: fr, data: {legal_document: true} .col-md-4 %p.domain-general-help= t(:domain_general_help).html_safe %p.domain-admin-contact-help= t(:domain_admin_contact_help).html_safe diff --git a/app/views/shared/_title.haml b/app/views/shared/_title.haml index 3832a7664..c6ab477fa 100644 --- a/app/views/shared/_title.haml +++ b/app/views/shared/_title.haml @@ -4,7 +4,7 @@ .row .col-sm-6 %h1.text-center-xs - = truncate(name, length: 35) + = content_for?(:page_name) ? yield(:page_name) : truncate(name, length: 35) .col-sm-6 %h1.text-right.text-center-xs = yield :actions diff --git a/config/application-example.yml b/config/application-example.yml index cf6e26357..4db92097f 100644 --- a/config/application-example.yml +++ b/config/application-example.yml @@ -88,6 +88,16 @@ repp_url: 'https://repp.gitlab.eu/repp/v1/' # restful_whois_url: 'https://restful-whois.example.com' +# +# Estonian Business Registry +# +# config/secrets.yml --- arireg: {username, password} +arireg_username: 'kasutaja' +arireg_password: 'parool' +# config/environments/production.rb --- Soap::Arireg.wsdl, Soap::Arireg.host +arireg_wsdl: 'lib/schemas/testariport.wsdl' # https://demo-ariregxml.rik.ee:447/testariport/?wsdl +#arireg_wsdl: 'lib/schemas/ariport.wsdl' # https://ariregxml.rik.ee/ariport/?wsdl +arireg_host: 'https://demo-ariregxml.rik.ee:447' # https://ariregxml.rik.ee/ # # REGISTRAR AND REGISTRANT diff --git a/config/application.rb b/config/application.rb index 7734cc6e9..2121039dc 100644 --- a/config/application.rb +++ b/config/application.rb @@ -7,6 +7,8 @@ require 'action_controller/railtie' require 'action_mailer/railtie' require 'action_view/railtie' require 'sprockets/railtie' +require 'csv' +require 'rails/all' # require "rails/test_unit/railtie" # Require the gems listed in Gemfile, including any gems diff --git a/config/deploy-example.rb b/config/deploy-example.rb index f6cd5dee6..33bf49247 100644 --- a/config/deploy-example.rb +++ b/config/deploy-example.rb @@ -144,6 +144,7 @@ set :shared_paths, [ 'config/initializers/current_commit_hash.rb', 'log', 'public/system', + 'public/assets', 'export/zonefiles', 'import/bank_statements', 'import/legal_documents', @@ -180,6 +181,9 @@ task setup: :environment do queue! %(mkdir -p "#{deploy_to}/shared/public/system") queue! %(chmod g+rx,u+rwx "#{deploy_to}/shared/public/system") + queue! %(mkdir -p "#{deploy_to}/shared/public/assets") + queue! %(chmod g+rx,u+rwx "#{deploy_to}/shared/public/assets") + queue! %(mkdir -p "#{deploy_to}/shared/export/zonefiles") queue! %(chmod g+rx,u+rwx "#{deploy_to}/shared/export/zonefiles") @@ -219,6 +223,7 @@ task deploy: :environment do invoke :'deploy:link_shared_paths' invoke :'bundle:install' invoke :'rails:db_migrate' + invoke :'rails:assets_precompile' to :launch do invoke :restart invoke :'deploy:cleanup' diff --git a/config/environments/production.rb b/config/environments/production.rb index 58258e710..0c8989a3b 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -30,7 +30,7 @@ Rails.application.configure do config.assets.compile = false # Generate digests for assets URLs. - config.assets.digest = false + config.assets.digest = true # Version of your assets, change this if you want to expire all your assets. config.assets.version = '1.0' @@ -70,7 +70,7 @@ Rails.application.configure do config.i18n.fallbacks = true # Send deprecation notices to registered listeners. - config.active_support.deprecation = :notify + config.active_support.deprecation = :log # Disable automatic flushing of the log to improve performance. # config.autoflush_log = false diff --git a/config/environments/staging.rb b/config/environments/staging.rb index 0a5e3ecae..242cc29df 100644 --- a/config/environments/staging.rb +++ b/config/environments/staging.rb @@ -30,7 +30,7 @@ Rails.application.configure do config.assets.compile = false # Generate digests for assets URLs. - config.assets.digest = false + config.assets.digest = true # Version of your assets, change this if you want to expire all your assets. config.assets.version = '1.0' @@ -43,7 +43,7 @@ Rails.application.configure do # config.force_ssl = true # Set to :debug to see everything in the log. - config.log_level = :info + config.log_level = :debug # Prepend all log lines with the following tags. config.log_tags = [:subdomain, :uuid, :remote_ip] @@ -70,7 +70,7 @@ Rails.application.configure do config.i18n.fallbacks = true # Send deprecation notices to registered listeners. - config.active_support.deprecation = :notify + config.active_support.deprecation = :log # Disable automatic flushing of the log to improve performance. # config.autoflush_log = false diff --git a/config/initializers/eis_ransack.rb b/config/initializers/eis_ransack.rb new file mode 100644 index 000000000..c23791ef7 --- /dev/null +++ b/config/initializers/eis_ransack.rb @@ -0,0 +1,40 @@ +# A custom initializer that enables sorting via custom scopes in Ransack (like the same feature in MetaSearch) + +module Ransack + module Adapters + module ActiveRecord + class Context < ::Ransack::Context + + # Allows for sorting by custom scopes + # + # + # Define your custom scopes in your model, e. g. sort_by_title_asc and sort_by_title_desc + # (The scopes would sort by some calculated column or a column added via some crazy join, etc.) + # + # In your sort links refer to the scopes like to standard fields, e. g. + # <%= sort_link(@q, :title, 'Crazy calculated title') %> + def evaluate(search, opts = {}) + viz = Visitor.new + relation = @object.where(viz.accept(search.base)) + if search.sorts.any? + custom_scopes = search.sorts.select do |s| + custom_scope_name = :"sort_by_#{s.name}_#{s.dir}" + relation.respond_to?(custom_scope_name) + end + attribute_scopes = search.sorts - custom_scopes + + relation = relation.except(:order) + + custom_scopes.each do |s| + custom_scope_name = :"sort_by_#{s.name}_#{s.dir}" + relation = relation.public_send(custom_scope_name) + end + + relation = relation.reorder(viz.accept(attribute_scopes)) if attribute_scopes.any? + end + opts[:distinct] ? relation.distinct : relation + end + end + end + end +end \ No newline at end of file diff --git a/config/initializers/initial_settings.rb b/config/initializers/initial_settings.rb index 1b25ddeb3..b6a60c5e8 100644 --- a/config/initializers/initial_settings.rb +++ b/config/initializers/initial_settings.rb @@ -28,8 +28,13 @@ if con.present? && con.table_exists?('settings') Setting.save_default(:client_side_status_editing_enabled, false) + Setting.save_default(:days_to_keep_business_registry_cache, 2) + Setting.save_default(:invoice_number_min, 131050) Setting.save_default(:invoice_number_max, 149999) + Setting.save_default(:directo_monthly_number_min, 309901) + Setting.save_default(:directo_monthly_number_max, 309999) + Setting.save_default(:directo_monthly_number_last, 309901) Setting.save_default(:days_to_keep_invoices_active, 30) Setting.save_default(:days_to_keep_overdue_invoices_active, 30) Setting.save_default(:minimum_deposit, 0.0) diff --git a/config/locales/en.yml b/config/locales/en.yml index 8a79c45d7..6372d401d 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -77,6 +77,7 @@ en: registrant: blank: 'Registrant is missing' not_found: 'Registrant not found' + cannot_be_missing: 'Parameter value policy error: registrant cannot be missing' domain_contacts: invalid: 'Contacts are invalid' not_found: 'Contact was not found' @@ -206,6 +207,10 @@ en: blank: 'Algorithm is missing' auth_info_pw: blank: 'Password is missing' + legal_document: + attributes: + body: + length: 'Parameter value policy error: legalDocument size should be more than 3kB' attributes: @@ -355,6 +360,7 @@ en: contact: 'Contact' credit_balance: 'Credit balance' starting_balance: 'Starting balance' + destroyed: 'Destroyed' domain_transfer_requested: 'Domain transfer requested!' domain_transfer_approved: 'Domain transfer approved!' @@ -537,6 +543,7 @@ en: switch_to: Switch to admin_menu: Admin domain_transfer_was_approved: 'Domain transfer was approved, associated contacts were: %{contacts} and registrant was %{registrant}' + business_registry_service_not_available: "Business Registry service Ärireg is not available" # DEPP activemodel: @@ -931,3 +938,11 @@ en: if_auth_info_is_left_empty_it_will_be_auto_generated: 'If auth info is left empty, it will be auto generated.' each_domain_name_must_end_with_colon_sign: 'Each domain name must end with colon (:) sign.' expiration_remind_subject: 'The %{name} domain has expired' + personal_domain_verification_url: 'Personal domain verification url' + available_verification_url_not_found: 'Available verification url not found, for domain.' + contact_already_associated_with_the_domain: 'Object association prohibits operation, contact already associated with the domain' + add_reserved_domain: 'Add domain to reserved list' + add_blocked_domain: 'Add domain to blocked list' + edit_pw: 'Edit Pw' + optional: 'Optional' + test_registrar: "Test registrar" diff --git a/config/routes.rb b/config/routes.rb index 9dd7faf7d..ea5b55a7e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -103,6 +103,17 @@ Rails.application.routes.draw do namespace :registrant do root 'domains#index' + resources :domains do + collection do + get :download_list + end + + member do + get 'domain_verification_url' + end + + end + # resources :invoices do # member do # get 'download_pdf' @@ -141,25 +152,19 @@ Rails.application.routes.draw do end end + resources :registrars do + resources :api_users + resources :white_ips + collection do + get :search + end + end + + resources :contacts resources :whois - # resources :contacts do - # member do - # get 'delete' - # end - - # collection do - # get 'check' - # end - # end - - # resource :poll do - # collection do - # post 'confirm_keyrelay' - # post 'confirm_transfer' - # end - # end end + # ADMIN ROUTES namespace :admin do resources :keyrelays @@ -204,8 +209,16 @@ Rails.application.routes.draw do resources :settings - resources :blocked_domains - resources :reserved_domains + resources :blocked_domains do + member do + get 'delete' + end + end + resources :reserved_domains do + member do + get 'delete' + end + end resources :registrars do resources :api_users diff --git a/config/schedule.rb b/config/schedule.rb index f3bbad764..b364f59e0 100644 --- a/config/schedule.rb +++ b/config/schedule.rb @@ -31,7 +31,7 @@ if @cron_group == 'registry' # end every :day, at: '12:20am' do - runner 'Domain.clean_expired_pendings' + runner 'DomainCron.clean_expired_pendings' end every 3.hours do @@ -39,19 +39,19 @@ if @cron_group == 'registry' end every 42.minutes do - runner 'Domain.destroy_delete_candidates' + runner 'DomainCron.destroy_delete_candidates' end every 45.minutes do - runner 'Domain.start_expire_period' + runner 'DomainCron.start_expire_period' end every 50.minutes do - runner 'Domain.start_delete_period' + runner 'DomainCron.start_delete_period' end every 52.minutes do - runner 'Domain.start_redemption_grace_period' + runner 'DomainCron.start_redemption_grace_period' end every :day, at: '19:00pm' do diff --git a/db/migrate/20151209122816_create_business_registry_caches.rb b/db/migrate/20151209122816_create_business_registry_caches.rb new file mode 100644 index 000000000..3d7766a60 --- /dev/null +++ b/db/migrate/20151209122816_create_business_registry_caches.rb @@ -0,0 +1,13 @@ +class CreateBusinessRegistryCaches < ActiveRecord::Migration + def change + create_table :business_registry_caches do |t| + t.string :ident + t.string :ident_country_code + t.datetime :retrieved_on + t.string :associated_businesses, array: true + t.timestamps null: false + end + + add_index :business_registry_caches, :ident + end +end diff --git a/db/migrate/20160218102355_index_domain_statuses.rb b/db/migrate/20160218102355_index_domain_statuses.rb new file mode 100644 index 000000000..d7bb787cb --- /dev/null +++ b/db/migrate/20160218102355_index_domain_statuses.rb @@ -0,0 +1,5 @@ +class IndexDomainStatuses < ActiveRecord::Migration + def change + add_index :domains, :statuses, using: :gin + end +end diff --git a/db/migrate/20160304125933_add_invoice_number_to_directo.rb b/db/migrate/20160304125933_add_invoice_number_to_directo.rb new file mode 100644 index 000000000..e639e8910 --- /dev/null +++ b/db/migrate/20160304125933_add_invoice_number_to_directo.rb @@ -0,0 +1,6 @@ +class AddInvoiceNumberToDirecto < ActiveRecord::Migration + def change + add_column :directos, :invoice_number, :string + execute "UPDATE directos d SET invoice_number=i.number FROM invoices i WHERE d.item_type='Invoice' AND d.item_id=i.id" + end +end diff --git a/db/migrate/20160311085957_add_test_registrar_to_registrar.rb b/db/migrate/20160311085957_add_test_registrar_to_registrar.rb new file mode 100644 index 000000000..b8b05cbd7 --- /dev/null +++ b/db/migrate/20160311085957_add_test_registrar_to_registrar.rb @@ -0,0 +1,5 @@ +class AddTestRegistrarToRegistrar < ActiveRecord::Migration + def change + add_column :registrars, :test_registrar, :boolean, default: false + end +end diff --git a/db/migrate/20160405131315_add_request_to_directo.rb b/db/migrate/20160405131315_add_request_to_directo.rb new file mode 100644 index 000000000..2efb95f7d --- /dev/null +++ b/db/migrate/20160405131315_add_request_to_directo.rb @@ -0,0 +1,5 @@ +class AddRequestToDirecto < ActiveRecord::Migration + def change + add_column :directos, :request, :text + end +end diff --git a/db/schema-read-only.rb b/db/schema-read-only.rb index 78722223a..2d410461c 100644 --- a/db/schema-read-only.rb +++ b/db/schema-read-only.rb @@ -11,11 +11,12 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160108135436) do +ActiveRecord::Schema.define(version: 20160304125933) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" enable_extension "hstore" + enable_extension "btree_gist" create_table "account_activities", force: :cascade do |t| t.integer "account_id" @@ -108,6 +109,7 @@ ActiveRecord::Schema.define(version: 20160108135436) do t.datetime "updated_at" t.string "creator_str" t.string "updator_str" + t.boolean "in_directo", default: false end create_table "banklink_transactions", force: :cascade do |t| @@ -144,6 +146,17 @@ ActiveRecord::Schema.define(version: 20160108135436) do add_index "blocked_domains", ["name"], name: "index_blocked_domains_on_name", using: :btree + create_table "business_registry_caches", force: :cascade do |t| + t.string "ident" + t.string "ident_country_code" + t.datetime "retrieved_on" + t.string "associated_businesses", array: true + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + add_index "business_registry_caches", ["ident"], name: "index_business_registry_caches_on_ident", using: :btree + create_table "cached_nameservers", id: false, force: :cascade do |t| t.string "hostname", limit: 255 t.string "ipv4", limit: 255 @@ -241,6 +254,17 @@ ActiveRecord::Schema.define(version: 20160108135436) do t.datetime "created_at" end + create_table "directos", force: :cascade do |t| + t.integer "item_id" + t.string "item_type" + t.json "response" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.string "invoice_number" + end + + add_index "directos", ["item_type", "item_id"], name: "index_directos_on_item_type_and_item_id", using: :btree + create_table "dnskeys", force: :cascade do |t| t.integer "domain_id" t.integer "flags" @@ -345,6 +369,7 @@ ActiveRecord::Schema.define(version: 20160108135436) do add_index "domains", ["registrant_verification_asked_at"], name: "index_domains_on_registrant_verification_asked_at", using: :btree add_index "domains", ["registrant_verification_token"], name: "index_domains_on_registrant_verification_token", using: :btree add_index "domains", ["registrar_id"], name: "index_domains_on_registrar_id", using: :btree + add_index "domains", ["statuses"], name: "index_domains_on_statuses", using: :gin create_table "epp_sessions", force: :cascade do |t| t.string "session_id" @@ -372,20 +397,20 @@ ActiveRecord::Schema.define(version: 20160108135436) do add_index "invoice_items", ["invoice_id"], name: "index_invoice_items_on_invoice_id", using: :btree create_table "invoices", force: :cascade do |t| - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.string "invoice_type", null: false - t.datetime "due_date", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.string "invoice_type", null: false + t.datetime "due_date", null: false t.string "payment_term" - t.string "currency", null: false + t.string "currency", null: false t.string "description" t.string "reference_no" - t.decimal "vat_prc", precision: 10, scale: 2, null: false + t.decimal "vat_prc", precision: 10, scale: 2, null: false t.datetime "paid_at" t.integer "seller_id" - t.string "seller_name", null: false + t.string "seller_name", null: false t.string "seller_reg_no" - t.string "seller_iban", null: false + t.string "seller_iban", null: false t.string "seller_bank" t.string "seller_swift" t.string "seller_vat_no" @@ -399,7 +424,7 @@ ActiveRecord::Schema.define(version: 20160108135436) do t.string "seller_email" t.string "seller_contact_name" t.integer "buyer_id" - t.string "buyer_name", null: false + t.string "buyer_name", null: false t.string "buyer_reg_no" t.string "buyer_country_code" t.string "buyer_state" @@ -414,6 +439,7 @@ ActiveRecord::Schema.define(version: 20160108135436) do t.integer "number" t.datetime "cancelled_at" t.decimal "sum_cache", precision: 10, scale: 2 + t.boolean "in_directo", default: false end add_index "invoices", ["buyer_id"], name: "index_invoices_on_buyer_id", using: :btree @@ -592,7 +618,7 @@ ActiveRecord::Schema.define(version: 20160108135436) do t.integer "item_id", null: false t.string "event", null: false t.string "whodunnit" - t.json "object" + t.jsonb "object" t.json "object_changes" t.datetime "created_at" t.string "session" @@ -623,7 +649,7 @@ ActiveRecord::Schema.define(version: 20160108135436) do t.integer "item_id", null: false t.string "event", null: false t.string "whodunnit" - t.json "object" + t.jsonb "object" t.json "object_changes" t.datetime "created_at" t.string "session" @@ -683,7 +709,7 @@ ActiveRecord::Schema.define(version: 20160108135436) do t.integer "item_id", null: false t.string "event", null: false t.string "whodunnit" - t.json "object" + t.jsonb "object" t.json "object_changes" t.datetime "created_at" t.text "nameserver_ids", default: [], array: true @@ -761,7 +787,7 @@ ActiveRecord::Schema.define(version: 20160108135436) do t.integer "item_id", null: false t.string "event", null: false t.string "whodunnit" - t.json "object" + t.jsonb "object" t.json "object_changes" t.datetime "created_at" t.string "session" @@ -897,10 +923,10 @@ ActiveRecord::Schema.define(version: 20160108135436) do create_table "nameservers", force: :cascade do |t| t.string "hostname" - t.string "ipv4", default: [], array: true + t.string "ipv4", array: true t.datetime "created_at" t.datetime "updated_at" - t.string "ipv6", default: [], array: true + t.string "ipv6", array: true t.integer "domain_id" t.string "creator_str" t.string "updator_str" @@ -992,6 +1018,7 @@ ActiveRecord::Schema.define(version: 20160108135436) do end add_index "registrars", ["code"], name: "index_registrars_on_code", using: :btree + add_index "registrars", ["legacy_id"], name: "index_registrars_on_legacy_id", using: :btree create_table "reserved_domains", force: :cascade do |t| t.datetime "created_at" diff --git a/db/structure.sql b/db/structure.sql index cf413eff1..78228b693 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -23,6 +23,20 @@ CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog; COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language'; +-- +-- Name: btree_gist; Type: EXTENSION; Schema: -; Owner: - +-- + +CREATE EXTENSION IF NOT EXISTS btree_gist WITH SCHEMA public; + + +-- +-- Name: EXTENSION btree_gist; Type: COMMENT; Schema: -; Owner: - +-- + +COMMENT ON EXTENSION btree_gist IS 'support for indexing common datatypes in GiST'; + + -- -- Name: hstore; Type: EXTENSION; Schema: -; Owner: - -- @@ -39,140 +53,6 @@ COMMENT ON EXTENSION hstore IS 'data type for storing sets of (key, value) pairs SET search_path = public, pg_catalog; --- --- Name: change_ident_country(); Type: FUNCTION; Schema: public; Owner: - --- - -CREATE FUNCTION change_ident_country() RETURNS boolean - LANGUAGE plpgsql - AS $_$ -DECLARE - changed BOOLEAN; - multiplier INT []; - multiplier2 INT []; - multiplier3 INT []; - multiplier4 INT []; - r RECORD; - control TEXT; - total INT; - i INT; - mod INT; - counter INT; -BEGIN - - multiplier := ARRAY [1, 2, 3, 4, 5, 6, 7, 8, 9, 1]; - - multiplier2 := ARRAY [3, 4, 5, 6, 7, 8, 9, 1, 2, 3]; - - multiplier3 := ARRAY [1, 2, 3, 4, 5, 6, 7]; - - multiplier4 := ARRAY [3, 4, 5, 6, 7, 8, 9]; - - FOR r IN SELECT id, ident FROM contacts WHERE ident_type = 'priv' /*AND ident_country_code IS NULL*/ - LOOP - IF (length(r.ident) = 11 AND (r.ident ~ '^[0-9]+$') AND (substring(r.ident, 1, 1) = '3' OR substring(r.ident, 1, 1) = '4' OR substring(r.ident, 1, 1) = '5' OR substring(r.ident, 1, 1) = '6')) - THEN - total := 0; - counter := 1; - FOREACH i IN ARRAY multiplier - LOOP - total := (total + (i * to_number(substring(r.ident, counter, 1), '9'))); - counter := (counter + 1); - END LOOP; - mod := (total % 11); - counter := 1; - - IF (mod >= 10) - THEN - total = 0; - FOREACH i IN ARRAY multiplier2 - LOOP - total := (total + (i * to_number(substring(r.ident, counter, 1), '9'))); - counter := (counter + 1); - END LOOP; - mod := (total % 11); - END IF; - - IF (mod < 10 AND substring(r.ident, 11, 1) = to_char(mod, 'FM999MI')) - THEN - UPDATE contacts SET ident_country_code = 'EE' WHERE id = r.id; - END IF; - total = 0; - END IF; - END LOOP; - - FOR r IN SELECT id, ident FROM contacts WHERE ident_type = 'org' - LOOP - IF (length(r.ident) = 8 AND (r.ident ~ '^[0-9]+$') AND (substring(r.ident, 1, 1) = '1' OR substring(r.ident, 1, 1) = '8' OR substring(r.ident, 1, 1) = '9')) - THEN - total := 0; - counter := 1; - FOREACH i IN ARRAY multiplier3 - LOOP - total := (total + (i * to_number(substring(r.ident, counter, 1), '9'))); - counter := (counter + 1); - END LOOP; - mod := total % 11; - total = 0; - counter := 1; - - IF (mod >= 10) - THEN - total = 0; - FOREACH i IN ARRAY multiplier4 - LOOP - total := (total + (i * to_number(substring(r.ident, counter, 1), '9'))); - counter := (counter + 1); - END LOOP; - mod := (total % 11); - END IF; - - IF (mod < 10 AND (substring(r.ident, 8, 1) = to_char(mod, 'FM999MI'))) - THEN - UPDATE contacts SET ident_country_code = 'EE' WHERE id = r.id; - END IF; - END IF; - END LOOP; - - - - RETURN changed; -END; -$_$; - - --- --- Name: change_ident_country(integer, text); Type: FUNCTION; Schema: public; Owner: - --- - -CREATE FUNCTION change_ident_country(id integer, type text) RETURNS boolean - LANGUAGE plpgsql - AS $_$ -DECLARE - changed BOOLEAN; - multiplier int[]; - multiplier2 int[]; - code int; -BEGIN - - multiplier := ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 1]; - - multiplier2 := ARRAY[3, 4, 5, 6, 7, 8, 9, 1, 2, 3]; - - code := (SELECT code FROM contacts WHERE id = 208 AND ident_country_code = 'EE'); - - - - UPDATE contacts - SET ident = '' - WHERE id = $1 and ident_type = $2 AND ident_country_code = 'EE' - AND ident = ''; - - RETURN changed; -END; -$_$; - - -- -- Name: fill_ident_country(); Type: FUNCTION; Schema: public; Owner: - -- @@ -222,12 +102,10 @@ CREATE FUNCTION fill_ident_country() RETURNS boolean END LOOP; mod := (total % 11); END IF; - IF (mod = 10) THEN mod := 0; END IF; - IF (substring(r.ident, 11, 1) = to_char(mod, 'FM999MI')) THEN UPDATE contacts SET ident_country_code = 'EE' WHERE id = r.id; @@ -291,7 +169,7 @@ CREATE FUNCTION generate_zonefile(i_origin character varying) RETURNS text ret text; BEGIN -- define filters - include_filter = '%' || i_origin; + include_filter = '%.' || i_origin; -- for %.%.% IF i_origin ~ '\.' THEN @@ -318,6 +196,10 @@ CREATE FUNCTION generate_zonefile(i_origin character varying) RETURNS text ret = concat(tmp_var, chr(10), chr(10)); + -- origin ns records + SELECT ns_records FROM zonefile_settings zf WHERE i_origin = zf.origin INTO tmp_var; + ret := concat(ret, '; Zone NS Records', chr(10), tmp_var, chr(10)); + -- ns records SELECT array_to_string( array( @@ -325,26 +207,17 @@ CREATE FUNCTION generate_zonefile(i_origin character varying) RETURNS text FROM domains d JOIN nameservers ns ON ns.domain_id = d.id WHERE d.name LIKE include_filter AND d.name NOT LIKE exclude_filter + AND NOT ('{serverHold,clientHold}' && d.statuses) ORDER BY d.name ), chr(10) ) INTO tmp_var; - ret := concat(ret, '; Zone NS Records', chr(10), tmp_var, chr(10), chr(10)); + ret := concat(ret, tmp_var, chr(10), chr(10)); - -- a glue records for origin nameservers - SELECT array_to_string( - array( - SELECT concat(ns.hostname, '. IN A ', ns.ipv4) - FROM nameservers ns - JOIN domains d ON d.id = ns.domain_id - WHERE d.name = i_origin - AND ns.hostname LIKE '%.' || d.name - AND ns.ipv4 IS NOT NULL AND ns.ipv4 <> '' - ), chr(10) - ) INTO tmp_var; - - ret := concat(ret, '; Zone A Records', chr(10), tmp_var); + -- origin a glue records + SELECT a_records FROM zonefile_settings zf WHERE i_origin = zf.origin INTO tmp_var; + ret := concat(ret, '; Zone A Records', chr(10), tmp_var, chr(10)); -- a glue records for other nameservers SELECT array_to_string( @@ -355,44 +228,16 @@ CREATE FUNCTION generate_zonefile(i_origin character varying) RETURNS text WHERE d.name LIKE include_filter AND d.name NOT LIKE exclude_filter AND ns.hostname LIKE '%.' || d.name AND d.name <> i_origin - AND ns.ipv4 IS NOT NULL AND ns.ipv4 <> '' - AND NOT EXISTS ( -- filter out glue records that already appeared in origin glue recrods - SELECT 1 FROM nameservers nsi - JOIN domains di ON nsi.domain_id = di.id - WHERE di.name = i_origin - AND nsi.hostname = ns.hostname - ) + AND ns.ipv4 IS NOT NULL AND ns.ipv4 <> '{}' + AND NOT ('{serverHold,clientHold}' && d.statuses) ), chr(10) ) INTO tmp_var; - -- TODO This is a possible subtitition to the previous query, stress testing is needed to see which is faster + ret := concat(ret, tmp_var, chr(10), chr(10)); - -- SELECT ns.* - -- FROM nameservers ns - -- JOIN domains d ON d.id = ns.domain_id - -- WHERE d.name LIKE '%ee' AND d.name NOT LIKE '%pri.ee' - -- AND ns.hostname LIKE '%.' || d.name - -- AND d.name <> 'ee' - -- AND ns.ipv4 IS NOT NULL AND ns.ipv4 <> '' - -- AND ns.hostname NOT IN ( - -- SELECT ns.hostname FROM domains d JOIN nameservers ns ON d.id = ns.domain_id WHERE d.name = 'ee' - -- ) - - ret := concat(ret, chr(10), tmp_var, chr(10), chr(10)); - - -- aaaa glue records for origin nameservers - SELECT array_to_string( - array( - SELECT concat(ns.hostname, '. IN AAAA ', ns.ipv6) - FROM nameservers ns - JOIN domains d ON d.id = ns.domain_id - WHERE d.name = i_origin - AND ns.hostname LIKE '%.' || d.name - AND ns.ipv6 IS NOT NULL AND ns.ipv6 <> '' - ), chr(10) - ) INTO tmp_var; - - ret := concat(ret, '; Zone AAAA Records', chr(10), tmp_var); + -- origin aaaa glue records + SELECT a4_records FROM zonefile_settings zf WHERE i_origin = zf.origin INTO tmp_var; + ret := concat(ret, '; Zone AAAA Records', chr(10), tmp_var, chr(10)); -- aaaa glue records for other nameservers SELECT array_to_string( @@ -403,17 +248,12 @@ CREATE FUNCTION generate_zonefile(i_origin character varying) RETURNS text WHERE d.name LIKE include_filter AND d.name NOT LIKE exclude_filter AND ns.hostname LIKE '%.' || d.name AND d.name <> i_origin - AND ns.ipv6 IS NOT NULL AND ns.ipv6 <> '' - AND NOT EXISTS ( -- filter out glue records that already appeared in origin glue recrods - SELECT 1 FROM nameservers nsi - JOIN domains di ON nsi.domain_id = di.id - WHERE di.name = i_origin - AND nsi.hostname = ns.hostname - ) + AND ns.ipv6 IS NOT NULL AND ns.ipv6 <> '{}' + AND NOT ('{serverHold,clientHold}' && d.statuses) ), chr(10) ) INTO tmp_var; - ret := concat(ret, chr(10), tmp_var, chr(10), chr(10)); + ret := concat(ret, tmp_var, chr(10), chr(10)); -- ds records SELECT array_to_string( @@ -424,7 +264,8 @@ CREATE FUNCTION generate_zonefile(i_origin character varying) RETURNS text ) FROM domains d JOIN dnskeys dk ON dk.domain_id = d.id - WHERE d.name LIKE include_filter AND d.name NOT LIKE exclude_filter + WHERE d.name LIKE include_filter AND d.name NOT LIKE exclude_filter AND dk.flags = 257 + AND NOT ('{serverHold,clientHold}' && d.statuses) ), chr(10) ) INTO tmp_var; @@ -652,7 +493,8 @@ CREATE TABLE bank_transactions ( created_at timestamp without time zone, updated_at timestamp without time zone, creator_str character varying, - updator_str character varying + updator_str character varying, + in_directo boolean DEFAULT false ); @@ -757,6 +599,40 @@ CREATE SEQUENCE blocked_domains_id_seq ALTER SEQUENCE blocked_domains_id_seq OWNED BY blocked_domains.id; +-- +-- Name: business_registry_caches; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE business_registry_caches ( + id integer NOT NULL, + ident character varying, + ident_country_code character varying, + retrieved_on timestamp without time zone, + associated_businesses character varying[], + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: business_registry_caches_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE business_registry_caches_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: business_registry_caches_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE business_registry_caches_id_seq OWNED BY business_registry_caches.id; + + -- -- Name: cached_nameservers; Type: TABLE; Schema: public; Owner: -; Tablespace: -- @@ -1000,6 +876,40 @@ CREATE SEQUENCE depricated_versions_id_seq ALTER SEQUENCE depricated_versions_id_seq OWNED BY depricated_versions.id; +-- +-- Name: directos; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE directos ( + id integer NOT NULL, + item_id integer, + item_type character varying, + response json, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + invoice_number character varying +); + + +-- +-- Name: directos_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE directos_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: directos_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE directos_id_seq OWNED BY directos.id; + + -- -- Name: dnskeys; Type: TABLE; Schema: public; Owner: -; Tablespace: -- @@ -1328,7 +1238,8 @@ CREATE TABLE invoices ( updator_str character varying, number integer, cancelled_at timestamp without time zone, - sum_cache numeric(10,2) + sum_cache numeric(10,2), + in_directo boolean DEFAULT false ); @@ -1771,7 +1682,7 @@ CREATE TABLE log_contacts ( item_id integer NOT NULL, event character varying NOT NULL, whodunnit character varying, - object json, + object jsonb, object_changes json, created_at timestamp without time zone, session character varying, @@ -1846,7 +1757,7 @@ CREATE TABLE log_dnskeys ( item_id integer NOT NULL, event character varying NOT NULL, whodunnit character varying, - object json, + object jsonb, object_changes json, created_at timestamp without time zone, session character varying, @@ -1994,7 +1905,7 @@ CREATE TABLE log_domains ( item_id integer NOT NULL, event character varying NOT NULL, whodunnit character varying, - object json, + object jsonb, object_changes json, created_at timestamp without time zone, nameserver_ids text[] DEFAULT '{}'::text[], @@ -2182,7 +2093,7 @@ CREATE TABLE log_nameservers ( item_id integer NOT NULL, event character varying NOT NULL, whodunnit character varying, - object json, + object jsonb, object_changes json, created_at timestamp without time zone, session character varying, @@ -2548,10 +2459,10 @@ ALTER SEQUENCE messages_id_seq OWNED BY messages.id; CREATE TABLE nameservers ( id integer NOT NULL, hostname character varying, - ipv4 character varying[] DEFAULT '{}'::character varying[], + ipv4 character varying[], created_at timestamp without time zone, updated_at timestamp without time zone, - ipv6 character varying[] DEFAULT '{}'::character varying[], + ipv6 character varying[], domain_id integer, creator_str character varying, updator_str character varying, @@ -3118,6 +3029,13 @@ ALTER TABLE ONLY banklink_transactions ALTER COLUMN id SET DEFAULT nextval('bank ALTER TABLE ONLY blocked_domains ALTER COLUMN id SET DEFAULT nextval('blocked_domains_id_seq'::regclass); +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY business_registry_caches ALTER COLUMN id SET DEFAULT nextval('business_registry_caches_id_seq'::regclass); + + -- -- Name: id; Type: DEFAULT; Schema: public; Owner: - -- @@ -3160,6 +3078,13 @@ ALTER TABLE ONLY delegation_signers ALTER COLUMN id SET DEFAULT nextval('delegat ALTER TABLE ONLY depricated_versions ALTER COLUMN id SET DEFAULT nextval('depricated_versions_id_seq'::regclass); +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY directos ALTER COLUMN id SET DEFAULT nextval('directos_id_seq'::regclass); + + -- -- Name: id; Type: DEFAULT; Schema: public; Owner: - -- @@ -3595,6 +3520,14 @@ ALTER TABLE ONLY blocked_domains ADD CONSTRAINT blocked_domains_pkey PRIMARY KEY (id); +-- +-- Name: business_registry_caches_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY business_registry_caches + ADD CONSTRAINT business_registry_caches_pkey PRIMARY KEY (id); + + -- -- Name: certificates_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- @@ -3643,6 +3576,14 @@ ALTER TABLE ONLY depricated_versions ADD CONSTRAINT depricated_versions_pkey PRIMARY KEY (id); +-- +-- Name: directos_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY directos + ADD CONSTRAINT directos_pkey PRIMARY KEY (id); + + -- -- Name: dnskeys_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- @@ -4109,6 +4050,13 @@ CREATE INDEX index_api_users_on_registrar_id ON api_users USING btree (registrar CREATE INDEX index_blocked_domains_on_name ON blocked_domains USING btree (name); +-- +-- Name: index_business_registry_caches_on_ident; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_business_registry_caches_on_ident ON business_registry_caches USING btree (ident); + + -- -- Name: index_cached_nameservers_on_hostname_and_ipv4_and_ipv6; Type: INDEX; Schema: public; Owner: -; Tablespace: -- @@ -4158,6 +4106,13 @@ CREATE INDEX index_contacts_on_registrar_id_and_ident_type ON contacts USING btr CREATE INDEX index_delegation_signers_on_domain_id ON delegation_signers USING btree (domain_id); +-- +-- Name: index_directos_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_directos_on_item_type_and_item_id ON directos USING btree (item_type, item_id); + + -- -- Name: index_dnskeys_on_delegation_signer_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- @@ -4256,6 +4211,13 @@ CREATE INDEX index_domains_on_registrant_verification_token ON domains USING btr CREATE INDEX index_domains_on_registrar_id ON domains USING btree (registrar_id); +-- +-- Name: index_domains_on_statuses; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_domains_on_statuses ON domains USING gin (statuses); + + -- -- Name: index_epp_sessions_on_session_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- @@ -4732,6 +4694,13 @@ CREATE INDEX index_registrant_verifications_on_domain_id ON registrant_verificat CREATE INDEX index_registrars_on_code ON registrars USING btree (code); +-- +-- Name: index_registrars_on_legacy_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_registrars_on_legacy_id ON registrars USING btree (legacy_id); + + -- -- Name: index_reserved_domains_on_name; Type: INDEX; Schema: public; Owner: -; Tablespace: -- @@ -4774,6 +4743,41 @@ CREATE INDEX index_whois_records_on_domain_id ON whois_records USING btree (doma CREATE INDEX index_whois_records_on_registrar_id ON whois_records USING btree (registrar_id); +-- +-- Name: log_contacts_object_legacy_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX log_contacts_object_legacy_id ON log_contacts USING btree ((((object ->> 'legacy_id'::text))::integer)); + + +-- +-- Name: log_contacts_object_legacy_id1; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX log_contacts_object_legacy_id1 ON log_contacts USING btree ((((object ->> 'legacy_id'::text))::integer)); + + +-- +-- Name: log_dnskeys_object_legacy_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX log_dnskeys_object_legacy_id ON log_contacts USING btree ((((object ->> 'legacy_domain_id'::text))::integer)); + + +-- +-- Name: log_domains_object_legacy_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX log_domains_object_legacy_id ON log_contacts USING btree ((((object ->> 'legacy_id'::text))::integer)); + + +-- +-- Name: log_nameservers_object_legacy_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX log_nameservers_object_legacy_id ON log_contacts USING btree ((((object ->> 'legacy_domain_id'::text))::integer)); + + -- -- Name: unique_data_migrations; Type: INDEX; Schema: public; Owner: -; Tablespace: -- @@ -5196,7 +5200,19 @@ INSERT INTO schema_migrations (version) VALUES ('20151130175654'); INSERT INTO schema_migrations (version) VALUES ('20151202123506'); -INSERT INTO schema_migrations (version) VALUES ('20160106092052'); +INSERT INTO schema_migrations (version) VALUES ('20151209122816'); + +INSERT INTO schema_migrations (version) VALUES ('20160106101725'); INSERT INTO schema_migrations (version) VALUES ('20160108135436'); +INSERT INTO schema_migrations (version) VALUES ('20160113143447'); + +INSERT INTO schema_migrations (version) VALUES ('20160118092453'); + +INSERT INTO schema_migrations (version) VALUES ('20160118092454'); + +INSERT INTO schema_migrations (version) VALUES ('20160218102355'); + +INSERT INTO schema_migrations (version) VALUES ('20160304125933'); + diff --git a/doc/epp/contact.md b/doc/epp/contact.md index 5db5ba3b4..684e43185 100644 --- a/doc/epp/contact.md +++ b/doc/epp/contact.md @@ -7,6 +7,11 @@ More info at http://en.wikipedia.org/wiki/Extensible_Provisioning_Protocol Contact Mapping protocol short version: +All values are limited to Unicode Latin characters if stricter limits are not specified. This includes unicode blocks +Basic Latin, Latin-1 Supplement, Latin Extended-A, Latin Extended-B, Latin Extended C, Latin Extended D, +Latin Extended Additional, Diacritics. +More info: https://en.wikipedia.org/wiki/Latin_script_in_Unicode + ### Contact create Field name Min-max Field description diff --git a/doc/epp/domain.md b/doc/epp/domain.md index 524deee1e..178ab629b 100644 --- a/doc/epp/domain.md +++ b/doc/epp/domain.md @@ -32,7 +32,7 @@ Domain name mapping protocol short version: 1-n 1 Allowed values: 0, 256, 257 1 Allowed values: 3 - 1 Allowed values: 3, 5, 6, 7, 8, 252, 253, 254, 255 + 1 Allowed values: 3, 5, 6, 7, 8, 10, 13, 14 1 Public key 1 Attribute: xmlns:eis="https://epp.tld.ee/schema/eis-1.0.xsd" 1 Base64 encoded document. @@ -81,7 +81,7 @@ Domain name mapping protocol short version: 1-n 1 Allowed values: 0, 256, 257 1 Allowed values: 3 - 1 Allowed values: 3, 5, 6, 7, 8, 252, 253, 254, 255 + 1 Allowed values: 3, 5, 6, 7, 8, 10, 13, 14 1 Public key 0-1 Attribute: xmlns:eis="https://epp.tld.ee/schema/eis-1.0.xsd" 0-1 Base64 encoded document. Required if registrant is changing. diff --git a/doc/epp/keyrelay.md b/doc/epp/keyrelay.md index f61765b2c..804fed6db 100644 --- a/doc/epp/keyrelay.md +++ b/doc/epp/keyrelay.md @@ -11,7 +11,7 @@ NB! Keyrelay not implemented. 1 1 Allowed values: 0, 256, 257 1 Allowed values: 3 - 1 Allowed values: 3, 5, 6, 7, 8, 252, 253, 254, 255 + 1 Allowed values: 3, 5, 6, 7, 8, 10, 13, 14 1 Public key 1 1 Domain password. Attribute: roid="String" diff --git a/lib/schemas/ariport.wsdl b/lib/schemas/ariport.wsdl new file mode 100644 index 000000000..7525c9227 --- /dev/null +++ b/lib/schemas/ariport.wsdl @@ -0,0 +1,510 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Teenuste nimekiri + + + + + + + Adapteri test + + + + + + + Ettevõtjaga seotud dokumentide loetelu päring + + + + + + + Ettevõtja esmakannete päring + + + + + + + Ettevõtja muudatuste loetelu tasuline päring + + + + + + + Ettevotja rekvisiitide päring + + + + + + + Ettevotja rekvisiitide fail + + + + + + + Isikute otsing + + + + + + + Klassifikaatorite päring + + + + + + + Ettevõtja majandusaasta aruande päring + + + + + + + Ettevõtja majandusaasta aruande loetelu päring + + + + + + + Ettevõtja detailandmete päring v5 + + + + + + + E-notar: toimiku dokumendi sisu + + + + + + + Ettevõtja lihtandmete päring v5 + + + + + + + Ettevõtja lihtandmete päring tasuta + + + + + + + Esindusõiguste päring v3 + + + + + + + Esindusõiguste päring v4 + + + + + + + Visuaalse Äriregistri ettevõtete-isikute vaheliste seoste päring + + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + + + + + Äriregister_uus + + + + diff --git a/lib/schemas/testariport.wsdl b/lib/schemas/testariport.wsdl new file mode 100644 index 000000000..25e3818b2 --- /dev/null +++ b/lib/schemas/testariport.wsdl @@ -0,0 +1,510 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Teenuste nimekiri + + + + + + + Adapteri test + + + + + + + Ettevõtjaga seotud dokumentide loetelu päring + + + + + + + Ettevõtja esmakannete päring + + + + + + + Ettevõtja muudatuste loetelu tasuline päring + + + + + + + Ettevotja rekvisiitide päring + + + + + + + Ettevotja rekvisiitide fail + + + + + + + Isikute otsing + + + + + + + Klassifikaatorite päring + + + + + + + Ettevõtja majandusaasta aruande päring + + + + + + + Ettevõtja majandusaasta aruande loetelu päring + + + + + + + Ettevõtja detailandmete päring v5 + + + + + + + E-notar: toimiku dokumendi sisu + + + + + + + Ettevõtja lihtandmete päring v5 + + + + + + + Ettevõtja lihtandmete päring tasuta + + + + + + + Esindusõiguste päring v3 + + + + + + + Esindusõiguste päring v4 + + + + + + + Visuaalse Äriregistri ettevõtete-isikute vaheliste seoste päring + + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + v1 + + + + + + + + + + + + + + Äriregister_uus + + + + diff --git a/lib/tasks/assets.rake b/lib/tasks/assets.rake deleted file mode 100644 index 253585726..000000000 --- a/lib/tasks/assets.rake +++ /dev/null @@ -1,18 +0,0 @@ -Rake::Task["assets:precompile"].enhance do - Rake::Task["assets:non_digested"].invoke -end - -namespace :assets do - task non_digested: :environment do - manifest_path = Dir.glob(File.join(Rails.root, 'public/assets/.sprockets-manifest-*.json')).first - manifest_data = JSON.load(File.new(manifest_path)) - - manifest_data["assets"].each do |logical_path, digested_path| - FileUtils.cp("public/assets/#{digested_path}", "public/assets/#{logical_path}") - end - end -end - -task as: :environment do - system('RAILS_ENV=production rake assets:precompile') -end diff --git a/lib/tasks/convert.rake b/lib/tasks/convert.rake index ba0e547dc..35e68046c 100644 --- a/lib/tasks/convert.rake +++ b/lib/tasks/convert.rake @@ -32,5 +32,44 @@ namespace :convert do d.save! end end + + + desc 'Contact Address Country Code Upcase' + task country_code_upcase: :environment do + count = 0 + Contact.find_each do |c| + if c.country_code.present? && c.country_code != c.country_code.upcase + c.country_code = c.country_code.upcase + c.update_columns(country_code: c.country_code.upcase) + + count +=1 + puts "#{count} contacts has been changed" if count % 1000 == 0 + end + end + puts "Contacts change has been finished. Starting ContactVersions" + + count = 0 + ContactVersion.find_each do |c| + if (if_object = (c.object && c.object["country_code"].present? && c.object["country_code"] != c.object["country_code"].upcase)) || + (if_changes = (c.object_changes && c.object_changes["country_code"].present? && c.object_changes["country_code"] != c.object_changes["country_code"].map{|e|e.try(:upcase)})) + + if if_object + h = c.object + h["country_code"] = h["country_code"].try(:upcase) + c.object = h + end + + if if_changes + h = c.object_changes + h["country_code"] = h["country_code"].map{|e|e.try(:upcase)} + c.object_changes = h + end + c.update_columns(object: c.object, object_changes: c.object_changes) + + count +=1 + puts "#{count} contact histories has been changed" if count % 1000 == 0 + end + end + end end diff --git a/lib/tasks/documents.rake b/lib/tasks/documents.rake new file mode 100644 index 000000000..5ae8fb4df --- /dev/null +++ b/lib/tasks/documents.rake @@ -0,0 +1,45 @@ +namespace :documents do + + desc 'Generate all' + task all: :environment do + Rake::Task['documents:log'].invoke + end + + desc 'Generate legaldoc versions' + task log: :environment do + start = Time.zone.now.to_f + puts '-----> Adding documets id for PaperTrail log...' + count = 0 + + LegalDocument.find_each do |x| + + next if x.documentable_id.blank? + + document_type = case x.documentable_type + when 'Domain' then DomainVersion + when 'Contact'then ContactVersion + end + + dc = document_type.where(item_id: x.documentable_id) + + dc.each do |y| + + if x.created_at < (y.created_at + (2*60)) && + x.created_at > (y.created_at - (2*60)) + + y.children[:legal_documents] = [x.id] + y.save + count =+1 + + else + + y.children[:legal_documents] = [] + y.save + + end + end + end + puts "-----> Log changed for #{count} rows in #{(Time.zone.now.to_f - start).round(2)} seconds" + end +end + diff --git a/lib/tasks/epp.rake b/lib/tasks/epp.rake new file mode 100644 index 000000000..e03835dad --- /dev/null +++ b/lib/tasks/epp.rake @@ -0,0 +1,19 @@ +namespace :epp do + + desc 'EPP actions' + task all: :environment do + Rake::Task['epp:trim_documents'].invoke + end + + desc 'Trim logs' + task trim_documents: :environment do + puts '-----> Running query' + sql = <<-SQL + UPDATE epp_logs SET request = regexp_replace(request, '', '[FILTERED]<\eis:legalDocument>'); + SQL + ApiLog::EppLog.connection.execute(sql) + + puts "-----> Query done" + end +end + diff --git a/lib/tasks/whois.rake b/lib/tasks/whois.rake index c8c3ba2a1..af1e33941 100644 --- a/lib/tasks/whois.rake +++ b/lib/tasks/whois.rake @@ -8,17 +8,17 @@ namespace :whois do print "\n-----> Update domains whois_records" Domain.find_in_batches.each do |group| - UpdateWhoisRecordJob.enqueue group.map(&:id), 'domain' + UpdateWhoisRecordJob.enqueue group.map(&:name), 'domain' end print "\n-----> Update blocked domains whois_records" BlockedDomain.find_in_batches.each do |group| - UpdateWhoisRecordJob.enqueue group.map(&:id), 'blocked' + UpdateWhoisRecordJob.enqueue group.map(&:name), 'blocked' end print "\n-----> Update reserved domains whois_records" ReservedDomain.find_in_batches.each do |group| - UpdateWhoisRecordJob.enqueue group.map(&:id), 'reserved' + UpdateWhoisRecordJob.enqueue group.map(&:name), 'reserved' end end diff --git a/lib/tasks/zonefile.rake b/lib/tasks/zonefile.rake index 797d340f0..f402528be 100644 --- a/lib/tasks/zonefile.rake +++ b/lib/tasks/zonefile.rake @@ -23,7 +23,7 @@ namespace :zonefile do exclude_filter := '%.%.' || i_origin; END IF; - SELECT ROUND(extract(epoch from now() at time zone 'utc')) INTO serial_num; + SELECT (extract(epoch from now() at time zone 'utc'))::int INTO serial_num; -- zonefile header SELECT concat( diff --git a/public/assets/.sprockets-manifest-48c2dd3ff16b86b70040480e74a50543.json b/public/assets/.sprockets-manifest-48c2dd3ff16b86b70040480e74a50543.json deleted file mode 100644 index c640e2e7e..000000000 --- a/public/assets/.sprockets-manifest-48c2dd3ff16b86b70040480e74a50543.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"admin-manifest-58660819bb55d95ee3f0c8149722a0e2ea507a3a45f24d22a2610d060bdc8dc0.css":{"logical_path":"admin-manifest.css","mtime":"2015-06-16T16:19:54+03:00","size":435358,"digest":"58660819bb55d95ee3f0c8149722a0e2ea507a3a45f24d22a2610d060bdc8dc0","integrity":"sha256-WGYIGbtV2V7j8MgUlyKg4upQejpF8k0iomENBgvcjcA="},"admin-manifest-025801216a3b153631239205b373c5e4ac42d55cc9a53960d3c485b5eed9d467.js":{"logical_path":"admin-manifest.js","mtime":"2015-06-08T14:38:06+03:00","size":712602,"digest":"025801216a3b153631239205b373c5e4ac42d55cc9a53960d3c485b5eed9d467","integrity":"sha256-AlgBIWo7FTYxI5IFs3PF5KxC1VzJpTlg08SFte7Z1Gc="},"registrar-manifest-70dd177301fef149b726705917e97491911b4a74c1760a223eaefaaf3918a38b.css":{"logical_path":"registrar-manifest.css","mtime":"2015-06-16T16:19:54+03:00","size":475725,"digest":"70dd177301fef149b726705917e97491911b4a74c1760a223eaefaaf3918a38b","integrity":"sha256-cN0XcwH+8Um3JnBZF+l0kZEbSnTBdgoiPq76rzkYo4s="},"registrar-manifest-037217137e7dd50d2a0c4aec309e532b9cd2696de45c826cc0c4ff8bf58025e6.js":{"logical_path":"registrar-manifest.js","mtime":"2015-06-19T15:29:08+03:00","size":730835,"digest":"037217137e7dd50d2a0c4aec309e532b9cd2696de45c826cc0c4ff8bf58025e6","integrity":"sha256-A3IXE3591Q0qDErsMJ5TK5zSaW3kXIJswMT/i/WAJeY="},"registrant-manifest-6bfceed2fd52330f303b890fa9d229b1ecd097fda1b7df2db41829b8c25d40c0.css":{"logical_path":"registrant-manifest.css","mtime":"2015-06-16T16:19:54+03:00","size":476257,"digest":"6bfceed2fd52330f303b890fa9d229b1ecd097fda1b7df2db41829b8c25d40c0","integrity":"sha256-a/zu0v1SMw8wO4kPqdIpsezQl/2ht98ttBgpuMJdQMA="},"registrant-manifest-037217137e7dd50d2a0c4aec309e532b9cd2696de45c826cc0c4ff8bf58025e6.js":{"logical_path":"registrant-manifest.js","mtime":"2015-06-19T15:29:08+03:00","size":730835,"digest":"037217137e7dd50d2a0c4aec309e532b9cd2696de45c826cc0c4ff8bf58025e6","integrity":"sha256-A3IXE3591Q0qDErsMJ5TK5zSaW3kXIJswMT/i/WAJeY="},"shared/pdf-2f929bf92af2ce26249b1b02bb998c63cf49da0ae4e3526f869fccd0af65ac3b.css":{"logical_path":"shared/pdf.css","mtime":"2015-05-15T15:29:32+03:00","size":353119,"digest":"2f929bf92af2ce26249b1b02bb998c63cf49da0ae4e3526f869fccd0af65ac3b","integrity":"sha256-L5Kb+SryziYkmxsCu5mMY89J2grk41Jvhp/M0K9lrDs="},"select2-d6b5d8d83dbc18fb8d77c8761d331cd9e5123c9684950bab0406e98a24ac5ae8.png":{"logical_path":"select2.png","mtime":"2015-10-19T14:02:21+03:00","size":613,"digest":"d6b5d8d83dbc18fb8d77c8761d331cd9e5123c9684950bab0406e98a24ac5ae8","integrity":"sha256-1rXY2D28GPuNd8h2HTMc2eUSPJaElQurBAbpiiSsWug="},"select2-spinner-f6ecff617ec2ba7f559e6f535cad9b70a3f91120737535dab4d4548a6c83576c.gif":{"logical_path":"select2-spinner.gif","mtime":"2015-10-19T14:02:21+03:00","size":1849,"digest":"f6ecff617ec2ba7f559e6f535cad9b70a3f91120737535dab4d4548a6c83576c","integrity":"sha256-9uz/YX7Cun9Vnm9TXK2bcKP5ESBzdTXatNRUimyDV2w="},"select2x2-6fe28d687dc0ed4d96016238c608ba1e7198c9c9accfa0b360b78018b9fb9bc2.png":{"logical_path":"select2x2.png","mtime":"2015-10-19T14:02:21+03:00","size":845,"digest":"6fe28d687dc0ed4d96016238c608ba1e7198c9c9accfa0b360b78018b9fb9bc2","integrity":"sha256-b+KNaH3A7U2WAWI4xgi6HnGYycmsz6CzYLeAGLn7m8I="},"alpha-9ac45a6b3c13dd5c5cf1b5d18c6f24a537dd2e4598238527d232a3e2ea5b5947.png":{"logical_path":"alpha.png","mtime":"2015-10-06T14:16:22+03:00","size":7089,"digest":"9ac45a6b3c13dd5c5cf1b5d18c6f24a537dd2e4598238527d232a3e2ea5b5947","integrity":"sha256-msRaazwT3Vxc8bXRjG8kpTfdLkWYI4Un0jKj4upbWUc="},"bg-b8036abd2f0f36e3ab54d5d5b25b0fbac11d63ec6106d959df3fa180b379de05.jpg":{"logical_path":"bg.jpg","mtime":"2015-10-06T14:16:22+03:00","size":69058,"digest":"b8036abd2f0f36e3ab54d5d5b25b0fbac11d63ec6106d959df3fa180b379de05","integrity":"sha256-uANqvS8PNuOrVNXVslsPusEdY+xhBtlZ3z+hgLN53gU="},"danske-07a4395cc406785da129414e15872fe1d6a4f6f6da0066da6701b56cdb72ea96.png":{"logical_path":"danske.png","mtime":"2015-10-06T14:16:22+03:00","size":1130,"digest":"07a4395cc406785da129414e15872fe1d6a4f6f6da0066da6701b56cdb72ea96","integrity":"sha256-B6Q5XMQGeF2hKUFOFYcv4dak9vbaAGbaZwG1bNty6pY="},"development-0b993e22410c7952394ac19ce3b41b722a97b93138a9a002091e1e5226d29bf5.png":{"logical_path":"development.png","mtime":"2015-10-06T14:16:22+03:00","size":14496,"digest":"0b993e22410c7952394ac19ce3b41b722a97b93138a9a002091e1e5226d29bf5","integrity":"sha256-C5k+IkEMeVI5SsGc47QbciqXuTE4qaACCR4eUibSm/U="},"eis-logo-et-86a549d266cda73e3225c5eeba14532c59d498e1fd980ec129fded68da8bb307.png":{"logical_path":"eis-logo-et.png","mtime":"2015-10-06T14:16:22+03:00","size":1440,"digest":"86a549d266cda73e3225c5eeba14532c59d498e1fd980ec129fded68da8bb307","integrity":"sha256-hqVJ0mbNpz4yJcXuuhRTLFnUmOH9mA7BKf3taNqLswc="},"favicon-309e00e2f78f9a2b042abc2806a8a4ed9cf6bb5d3f00ccc0985b1308bfd86c49.ico":{"logical_path":"favicon.ico","mtime":"2015-10-06T14:16:22+03:00","size":1150,"digest":"309e00e2f78f9a2b042abc2806a8a4ed9cf6bb5d3f00ccc0985b1308bfd86c49","integrity":"sha256-MJ4A4vePmisEKrwoBqik7Zz2u10/AMzAmFsTCL/YbEk="},"id_card-ea506a49b25c8de4e68e786d90f5ec5defb6c8e895b90f2f129815f5e550fe8e.gif":{"logical_path":"id_card.gif","mtime":"2015-10-06T14:16:22+03:00","size":564,"digest":"ea506a49b25c8de4e68e786d90f5ec5defb6c8e895b90f2f129815f5e550fe8e","integrity":"sha256-6lBqSbJcjeTmjnhtkPXsXe+2yOiVuQ8vEpgV9eVQ/o4="},"lhv-4d09d3126a05df392b73c54fa9b1eb605798c2e9bd361cf44500f73038832030.png":{"logical_path":"lhv.png","mtime":"2015-10-06T14:16:22+03:00","size":3417,"digest":"4d09d3126a05df392b73c54fa9b1eb605798c2e9bd361cf44500f73038832030","integrity":"sha256-TQnTEmoF3zkrc8VPqbHrYFeYwum9Nhz0RQD3MDiDIDA="},"mid-275543ecea377debe1ac892470f3aea4f7e7f0f9089fc0fbea4de410742e5239.gif":{"logical_path":"mid.gif","mtime":"2015-10-06T14:16:22+03:00","size":1566,"digest":"275543ecea377debe1ac892470f3aea4f7e7f0f9089fc0fbea4de410742e5239","integrity":"sha256-J1VD7Oo3fevhrIkkcPOupPfn8PkIn8D76k3kEHQuUjk="},"nordea-75c938c7436e0c8316f056be8df8acd0e8b16e09790e78f78da96d9f8633ef3b.png":{"logical_path":"nordea.png","mtime":"2015-10-06T14:16:22+03:00","size":1181,"digest":"75c938c7436e0c8316f056be8df8acd0e8b16e09790e78f78da96d9f8633ef3b","integrity":"sha256-dck4x0NuDIMW8Fa+jfis0Oixbgl5Dnj3jaltn4Yz7zs="},"registrar/bg-alpha-9ac45a6b3c13dd5c5cf1b5d18c6f24a537dd2e4598238527d232a3e2ea5b5947.png":{"logical_path":"registrar/bg-alpha.png","mtime":"2015-10-06T14:16:22+03:00","size":7089,"digest":"9ac45a6b3c13dd5c5cf1b5d18c6f24a537dd2e4598238527d232a3e2ea5b5947","integrity":"sha256-msRaazwT3Vxc8bXRjG8kpTfdLkWYI4Un0jKj4upbWUc="},"registrar/bg-development-0b993e22410c7952394ac19ce3b41b722a97b93138a9a002091e1e5226d29bf5.png":{"logical_path":"registrar/bg-development.png","mtime":"2015-10-06T14:16:22+03:00","size":14496,"digest":"0b993e22410c7952394ac19ce3b41b722a97b93138a9a002091e1e5226d29bf5","integrity":"sha256-C5k+IkEMeVI5SsGc47QbciqXuTE4qaACCR4eUibSm/U="},"registrar/bg-staging-6276f8c00911bc99f301f919e408ae3ef726c7378324ac55fd5d378ba3a4dc2d.png":{"logical_path":"registrar/bg-staging.png","mtime":"2015-10-06T14:16:22+03:00","size":12294,"digest":"6276f8c00911bc99f301f919e408ae3ef726c7378324ac55fd5d378ba3a4dc2d","integrity":"sha256-Ynb4wAkRvJnzAfkZ5AiuPvcmxzeDJKxV/V03i6Ok3C0="},"registrar/favicon-e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.ico":{"logical_path":"registrar/favicon.ico","mtime":"2015-10-06T14:16:22+03:00","size":0,"digest":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","integrity":"sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU="},"seb-9c9d943014cc4ee706244893cd8a2c4a8a7cc97bfbdef6a66e22c72f33d5f25e.png":{"logical_path":"seb.png","mtime":"2015-10-06T14:16:22+03:00","size":2439,"digest":"9c9d943014cc4ee706244893cd8a2c4a8a7cc97bfbdef6a66e22c72f33d5f25e","integrity":"sha256-nJ2UMBTMTucGJEiTzYosSop8yXv73vambiLHLzPV8l4="},"staging-6276f8c00911bc99f301f919e408ae3ef726c7378324ac55fd5d378ba3a4dc2d.png":{"logical_path":"staging.png","mtime":"2015-10-06T14:16:22+03:00","size":12294,"digest":"6276f8c00911bc99f301f919e408ae3ef726c7378324ac55fd5d378ba3a4dc2d","integrity":"sha256-Ynb4wAkRvJnzAfkZ5AiuPvcmxzeDJKxV/V03i6Ok3C0="},"swed-2cf45729062cf5fa634247ba372c579c97f382e5cc43fa111219077e7473fdbb.png":{"logical_path":"swed.png","mtime":"2015-10-06T14:16:22+03:00","size":1521,"digest":"2cf45729062cf5fa634247ba372c579c97f382e5cc43fa111219077e7473fdbb","integrity":"sha256-LPRXKQYs9fpjQke6NyxXnJfzguXMQ/oREhkHfnRz/bs="},"test-9ac45a6b3c13dd5c5cf1b5d18c6f24a537dd2e4598238527d232a3e2ea5b5947.png":{"logical_path":"test.png","mtime":"2015-10-06T14:16:22+03:00","size":7089,"digest":"9ac45a6b3c13dd5c5cf1b5d18c6f24a537dd2e4598238527d232a3e2ea5b5947","integrity":"sha256-msRaazwT3Vxc8bXRjG8kpTfdLkWYI4Un0jKj4upbWUc="},"admin/application-b1444f5083209e83d34a087d1ff78a91b8a3eb487815a1987cbc5a120bf4e48f.js":{"logical_path":"admin/application.js","mtime":"2015-06-08T11:23:15+03:00","size":396,"digest":"b1444f5083209e83d34a087d1ff78a91b8a3eb487815a1987cbc5a120bf4e48f","integrity":"sha256-sURPUIMgnoPTSgh9H/eKkbij60h4FaGYfLxaEgv05I8="},"registrar/application-8ad3d7cb40be14b5c7dd76340db3618c0cd651644aa1e29bff59cc32e454ea85.js":{"logical_path":"registrar/application.js","mtime":"2015-06-19T15:29:08+03:00","size":1107,"digest":"8ad3d7cb40be14b5c7dd76340db3618c0cd651644aa1e29bff59cc32e454ea85","integrity":"sha256-itPXy0C+FLXH3XY0DbNhjAzWUWRKoeKb/1nMMuRU6oU="},"etelkalight-webfont-baf7e35ab2f64bf1c6fa4476d3934c7422062995738fd9e5715b02f55002d7c0.eot":{"logical_path":"etelkalight-webfont.eot","mtime":"2015-10-06T14:16:23+03:00","size":23109,"digest":"baf7e35ab2f64bf1c6fa4476d3934c7422062995738fd9e5715b02f55002d7c0","integrity":"sha256-uvfjWrL2S/HG+kR205NMdCIGKZVzj9nlcVsC9VAC18A="},"etelkalight-webfont-2b575f6e4696d74957af27a7c7bb7976b7ca31d0ebe8ec25bb4c3494d5d16e24.svg":{"logical_path":"etelkalight-webfont.svg","mtime":"2015-10-06T14:16:23+03:00","size":64768,"digest":"2b575f6e4696d74957af27a7c7bb7976b7ca31d0ebe8ec25bb4c3494d5d16e24","integrity":"sha256-K1dfbkaW10lXryenx7t5drfKMdDr6Owlu0w0lNXRbiQ="},"etelkalight-webfont-f68a2db6346d864f82c3b3e725ee60b0217e91e46ec47f96710f70f996b61af1.ttf":{"logical_path":"etelkalight-webfont.ttf","mtime":"2015-10-06T14:16:23+03:00","size":49748,"digest":"f68a2db6346d864f82c3b3e725ee60b0217e91e46ec47f96710f70f996b61af1","integrity":"sha256-9oottjRthk+Cw7PnJe5gsCF+keRuxH+WcQ9w+Za2GvE="},"etelkalight-webfont-1ed38dbac6b817bf74bd46a98d61005aa2615db7ac743e4037364d1021084043.woff":{"logical_path":"etelkalight-webfont.woff","mtime":"2015-10-06T14:16:23+03:00","size":26204,"digest":"1ed38dbac6b817bf74bd46a98d61005aa2615db7ac743e4037364d1021084043","integrity":"sha256-HtONusa4F790vUapjWEAWqJhXbesdD5ANzZNECEIQEM="},"etelkalightbold-webfont-1d94cabe6fb55b05f746fe0aa51a7a503683d7afdb68360ed26bfac03e1b3c39.eot":{"logical_path":"etelkalightbold-webfont.eot","mtime":"2015-10-06T14:16:23+03:00","size":23707,"digest":"1d94cabe6fb55b05f746fe0aa51a7a503683d7afdb68360ed26bfac03e1b3c39","integrity":"sha256-HZTKvm+1WwX3Rv4KpRp6UDaD16/baDYO0mv6wD4bPDk="},"etelkalightbold-webfont-bb0c8e17b99b10f211be3531a51d6ad48a5c6e4670c8fb6160a329fa4758c555.svg":{"logical_path":"etelkalightbold-webfont.svg","mtime":"2015-10-06T14:16:23+03:00","size":62829,"digest":"bb0c8e17b99b10f211be3531a51d6ad48a5c6e4670c8fb6160a329fa4758c555","integrity":"sha256-uwyOF7mbEPIRvjUxpR1q1IpcbkZwyPthYKMp+kdYxVU="},"etelkalightbold-webfont-0f06d1e7f099578e1cc0e9b1875aca2a7128c0ca0d640fd504e97bae0b028429.ttf":{"logical_path":"etelkalightbold-webfont.ttf","mtime":"2015-10-06T14:16:23+03:00","size":51172,"digest":"0f06d1e7f099578e1cc0e9b1875aca2a7128c0ca0d640fd504e97bae0b028429","integrity":"sha256-DwbR5/CZV44cwOmxh1rKKnEowMoNZA/VBOl7rgsChCk="},"etelkalightbold-webfont-d608c036b3e3f04ca87a1c494f8d9e9620a729b2760b5eb1dcee52c4bc8e8805.woff":{"logical_path":"etelkalightbold-webfont.woff","mtime":"2015-10-06T14:16:23+03:00","size":26956,"digest":"d608c036b3e3f04ca87a1c494f8d9e9620a729b2760b5eb1dcee52c4bc8e8805","integrity":"sha256-1gjANrPj8EyoehxJT42eliCnKbJ2C16x3O5SxLyOiAU="},"etelkalightitalic-webfont-ce5cdffe6c589a6dc6bd2c482c718486ff5fb416ab01740750db325179e58654.eot":{"logical_path":"etelkalightitalic-webfont.eot","mtime":"2015-10-06T14:16:23+03:00","size":26426,"digest":"ce5cdffe6c589a6dc6bd2c482c718486ff5fb416ab01740750db325179e58654","integrity":"sha256-zlzf/mxYmm3GvSxILHGEhv9ftBarAXQHUNsyUXnlhlQ="},"etelkalightitalic-webfont-dd5353c2af4ea63e1d0e99ec5f1f85162cee0c4dd0a3840260a2606eefc3e517.svg":{"logical_path":"etelkalightitalic-webfont.svg","mtime":"2015-10-06T14:16:23+03:00","size":69857,"digest":"dd5353c2af4ea63e1d0e99ec5f1f85162cee0c4dd0a3840260a2606eefc3e517","integrity":"sha256-3VNTwq9Opj4dDpnsXx+FFizuDE3Qo4QCYKJgbu/D5Rc="},"etelkalightitalic-webfont-54eb91ad0e0b639f50be02b7c25836c99ad989185f5d2a240d60ea14a1b7384a.ttf":{"logical_path":"etelkalightitalic-webfont.ttf","mtime":"2015-10-06T14:16:23+03:00","size":57040,"digest":"54eb91ad0e0b639f50be02b7c25836c99ad989185f5d2a240d60ea14a1b7384a","integrity":"sha256-VOuRrQ4LY59QvgK3wlg2yZrZiRhfXSokDWDqFKG3OEo="},"etelkalightitalic-webfont-d1fb9621d40ef45104078a4a5b98ce4cba00872cf8ac56e299cf1397c146cac3.woff":{"logical_path":"etelkalightitalic-webfont.woff","mtime":"2015-10-06T14:16:23+03:00","size":29884,"digest":"d1fb9621d40ef45104078a4a5b98ce4cba00872cf8ac56e299cf1397c146cac3","integrity":"sha256-0fuWIdQO9FEEB4pKW5jOTLoAhyz4rFbimc8Tl8FGysM="},"infotexb-webfont-1951e43e1d9ab99b0d4998abba4aab34f3e68b337be90800db517e4a8d27d001.eot":{"logical_path":"infotexb-webfont.eot","mtime":"2015-10-06T14:16:23+03:00","size":23124,"digest":"1951e43e1d9ab99b0d4998abba4aab34f3e68b337be90800db517e4a8d27d001","integrity":"sha256-GVHkPh2auZsNSZirukqrNPPmizN76QgA21F+So0n0AE="},"infotexb-webfont-0dda72e34d0d0ced7693b55ed08acc60fb1a9036afd7736e432ac3f22f2e6fdf.svg":{"logical_path":"infotexb-webfont.svg","mtime":"2015-10-06T14:16:23+03:00","size":90188,"digest":"0dda72e34d0d0ced7693b55ed08acc60fb1a9036afd7736e432ac3f22f2e6fdf","integrity":"sha256-Ddpy400NDO12k7Ve0IrMYPsakDav13NuQyrD8i8ub98="},"infotexb-webfont-c0737d1e2edff50645e201bf99f68f2313502ee2bdeb2e56435ee24721baf5cd.ttf":{"logical_path":"infotexb-webfont.ttf","mtime":"2015-10-06T14:16:23+03:00","size":47396,"digest":"c0737d1e2edff50645e201bf99f68f2313502ee2bdeb2e56435ee24721baf5cd","integrity":"sha256-wHN9Hi7f9QZF4gG/mfaPIxNQLuK96y5WQ17iRyG69c0="},"infotexb-webfont-8da32e6db23c39390c55dd5ea8949714757fddba516c5db65e72867504493fbc.woff":{"logical_path":"infotexb-webfont.woff","mtime":"2015-10-06T14:16:23+03:00","size":26228,"digest":"8da32e6db23c39390c55dd5ea8949714757fddba516c5db65e72867504493fbc","integrity":"sha256-jaMubbI8OTkMVd1eqJSXFHV/3bpRbF22XnKGdQRJP7w="},"infotexm-webfont-74df99faeb66d8b02966b8884b860af03c359ed41d348ddb813dbcc3c460eb26.eot":{"logical_path":"infotexm-webfont.eot","mtime":"2015-10-06T14:16:23+03:00","size":23273,"digest":"74df99faeb66d8b02966b8884b860af03c359ed41d348ddb813dbcc3c460eb26","integrity":"sha256-dN+Z+utm2LApZriIS4YK8Dw1ntQdNI3bgT28w8Rg6yY="},"infotexm-webfont-0b52ef10620b8cb7289dc809aac67826d5031e6ab040194fdb7365dc83e95557.svg":{"logical_path":"infotexm-webfont.svg","mtime":"2015-10-06T14:16:23+03:00","size":90423,"digest":"0b52ef10620b8cb7289dc809aac67826d5031e6ab040194fdb7365dc83e95557","integrity":"sha256-C1LvEGILjLconcgJqsZ4JtUDHmqwQBlP23Nl3IPpVVc="},"infotexm-webfont-1d244d27a4ec4c1a5f98c82966faa26e7855c4292c730429477003b6dab5c08b.ttf":{"logical_path":"infotexm-webfont.ttf","mtime":"2015-10-06T14:16:23+03:00","size":47484,"digest":"1d244d27a4ec4c1a5f98c82966faa26e7855c4292c730429477003b6dab5c08b","integrity":"sha256-HSRNJ6TsTBpfmMgpZvqibnhVxCkscwQpR3ADttq1wIs="},"infotexm-webfont-872b5ab4e0b7de6655a52f137a3c99f1e7941fa91ff21a56550f2039834ee9d0.woff":{"logical_path":"infotexm-webfont.woff","mtime":"2015-10-06T14:16:23+03:00","size":26492,"digest":"872b5ab4e0b7de6655a52f137a3c99f1e7941fa91ff21a56550f2039834ee9d0","integrity":"sha256-hytatOC33mZVpS8TejyZ8eeUH6kf8hpWVQ8gOYNO6dA="},"jquery-ui/ui-bg_flat_0_aaaaaa_40x100-9a8492a580bf85d3e98ae8861fbd45567e5a1f83eeafcf9574da0399d5f602ab.png":{"logical_path":"jquery-ui/ui-bg_flat_0_aaaaaa_40x100.png","mtime":"2015-10-19T14:00:20+03:00","size":180,"digest":"9a8492a580bf85d3e98ae8861fbd45567e5a1f83eeafcf9574da0399d5f602ab","integrity":"sha256-moSSpYC/hdPpiuiGH71FVn5aH4Pur8+VdNoDmdX2Aqs="},"jquery-ui/ui-bg_flat_75_ffffff_40x100-39ab7ccd9f4e82579da78a9241265df288d8eb65dbbd7cf48aed2d0129887df5.png":{"logical_path":"jquery-ui/ui-bg_flat_75_ffffff_40x100.png","mtime":"2015-10-19T14:00:20+03:00","size":178,"digest":"39ab7ccd9f4e82579da78a9241265df288d8eb65dbbd7cf48aed2d0129887df5","integrity":"sha256-Oat8zZ9Ogledp4qSQSZd8ojY62XbvXz0iu0tASmIffU="},"jquery-ui/ui-bg_glass_55_fbf9ee_1x400-691597e8a40a891ea94d3589976ecfc33e6145c49422443b00ac2b5a0022964c.png":{"logical_path":"jquery-ui/ui-bg_glass_55_fbf9ee_1x400.png","mtime":"2015-10-19T14:00:20+03:00","size":120,"digest":"691597e8a40a891ea94d3589976ecfc33e6145c49422443b00ac2b5a0022964c","integrity":"sha256-aRWX6KQKiR6pTTWJl27Pwz5hRcSUIkQ7AKwrWgAilkw="},"jquery-ui/ui-bg_glass_65_ffffff_1x400-f0e6cd91b837d5c5644d026e5ffeccd907953317cd5c0f689901733afda260b2.png":{"logical_path":"jquery-ui/ui-bg_glass_65_ffffff_1x400.png","mtime":"2015-10-19T14:00:20+03:00","size":105,"digest":"f0e6cd91b837d5c5644d026e5ffeccd907953317cd5c0f689901733afda260b2","integrity":"sha256-8ObNkbg31cVkTQJuX/7M2QeVMxfNXA9omQFzOv2iYLI="},"jquery-ui/ui-bg_glass_75_dadada_1x400-c108f5cbf2dd9ec07a26530695ddd95e1664597ce6c056ae44c162cc2e28cec4.png":{"logical_path":"jquery-ui/ui-bg_glass_75_dadada_1x400.png","mtime":"2015-10-19T14:00:20+03:00","size":111,"digest":"c108f5cbf2dd9ec07a26530695ddd95e1664597ce6c056ae44c162cc2e28cec4","integrity":"sha256-wQj1y/LdnsB6JlMGld3ZXhZkWXzmwFauRMFizC4ozsQ="},"jquery-ui/ui-bg_glass_75_e6e6e6_1x400-ddf5dd4e0ef2b185e8bb0af7b6e90ebe74a84384cb4700658e76e754c8bfe550.png":{"logical_path":"jquery-ui/ui-bg_glass_75_e6e6e6_1x400.png","mtime":"2015-10-19T14:00:20+03:00","size":110,"digest":"ddf5dd4e0ef2b185e8bb0af7b6e90ebe74a84384cb4700658e76e754c8bfe550","integrity":"sha256-3fXdTg7ysYXouwr3tukOvnSoQ4TLRwBljnbnVMi/5VA="},"jquery-ui/ui-bg_glass_95_fef1ec_1x400-f6f1c1bedf1a0f37cfef81d12f5f012869d1ee7c984775a569827a1784d34f5c.png":{"logical_path":"jquery-ui/ui-bg_glass_95_fef1ec_1x400.png","mtime":"2015-10-19T14:00:20+03:00","size":119,"digest":"f6f1c1bedf1a0f37cfef81d12f5f012869d1ee7c984775a569827a1784d34f5c","integrity":"sha256-9vHBvt8aDzfP74HRL18BKGnR7nyYR3WlaYJ6F4TTT1w="},"jquery-ui/ui-bg_highlight-soft_75_cccccc_1x100-54270656df079c4da5182629a080fc633b6f84b87985eb016d25a560e2c38d4a.png":{"logical_path":"jquery-ui/ui-bg_highlight-soft_75_cccccc_1x100.png","mtime":"2015-10-19T14:00:20+03:00","size":101,"digest":"54270656df079c4da5182629a080fc633b6f84b87985eb016d25a560e2c38d4a","integrity":"sha256-VCcGVt8HnE2lGCYpoID8YztvhLh5hesBbSWlYOLDjUo="},"jquery-ui/ui-icons_222222_256x240-57adb0d65f4e91dacfee975d9574422bee7486c8a182d60133728c672f2cdbbc.png":{"logical_path":"jquery-ui/ui-icons_222222_256x240.png","mtime":"2015-10-19T14:00:20+03:00","size":4369,"digest":"57adb0d65f4e91dacfee975d9574422bee7486c8a182d60133728c672f2cdbbc","integrity":"sha256-V62w1l9OkdrP7pddlXRCK+50hsihgtYBM3KMZy8s27w="},"jquery-ui/ui-icons_2e83ff_256x240-20f8c6667afc48aa433ee9eb6d8a0584bdbd6b4a4a9091ff1e6b3adb31e63bd9.png":{"logical_path":"jquery-ui/ui-icons_2e83ff_256x240.png","mtime":"2015-10-19T14:00:20+03:00","size":4369,"digest":"20f8c6667afc48aa433ee9eb6d8a0584bdbd6b4a4a9091ff1e6b3adb31e63bd9","integrity":"sha256-IPjGZnr8SKpDPunrbYoFhL29a0pKkJH/Hms62zHmO9k="},"jquery-ui/ui-icons_454545_256x240-07460e843c3e59aaadbb34231e699e856a2980753c7a47b66447da5d9f93fb7f.png":{"logical_path":"jquery-ui/ui-icons_454545_256x240.png","mtime":"2015-10-19T14:00:20+03:00","size":4369,"digest":"07460e843c3e59aaadbb34231e699e856a2980753c7a47b66447da5d9f93fb7f","integrity":"sha256-B0YOhDw+WaqtuzQjHmmehWopgHU8eke2ZEfaXZ+T+38="},"jquery-ui/ui-icons_888888_256x240-ea2e29625de3463465e93b002b065f5833e05b97f7a052b1c141e754d62e1a8b.png":{"logical_path":"jquery-ui/ui-icons_888888_256x240.png","mtime":"2015-10-19T14:00:20+03:00","size":4369,"digest":"ea2e29625de3463465e93b002b065f5833e05b97f7a052b1c141e754d62e1a8b","integrity":"sha256-6i4pYl3jRjRl6TsAKwZfWDPgW5f3oFKxwUHnVNYuGos="},"jquery-ui/ui-icons_cd0a0a_256x240-1e32c6dbf5d3fd342f27a78aa881550d6412aa207f48468724a6a15402b6041b.png":{"logical_path":"jquery-ui/ui-icons_cd0a0a_256x240.png","mtime":"2015-10-19T14:00:20+03:00","size":4369,"digest":"1e32c6dbf5d3fd342f27a78aa881550d6412aa207f48468724a6a15402b6041b","integrity":"sha256-HjLG2/XT/TQvJ6eKqIFVDWQSqiB/SEaHJKahVAK2BBs="},"bootstrap/glyphicons-halflings-regular-13634da87d9e23f8c3ed9108ce1724d183a39ad072e73e1b3d8cbf646d2d0407.eot":{"logical_path":"bootstrap/glyphicons-halflings-regular.eot","mtime":"2015-10-19T13:57:56+03:00","size":20127,"digest":"13634da87d9e23f8c3ed9108ce1724d183a39ad072e73e1b3d8cbf646d2d0407","integrity":"sha256-E2NNqH2eI/jD7ZEIzhck0YOjmtBy5z4bPYy/ZG0tBAc="},"bootstrap/glyphicons-halflings-regular-42f60659d265c1a3c30f9fa42abcbb56bd4a53af4d83d316d6dd7a36903c43e5.svg":{"logical_path":"bootstrap/glyphicons-halflings-regular.svg","mtime":"2015-10-19T13:57:56+03:00","size":108738,"digest":"42f60659d265c1a3c30f9fa42abcbb56bd4a53af4d83d316d6dd7a36903c43e5","integrity":"sha256-QvYGWdJlwaPDD5+kKry7Vr1KU69Ng9MW1t16NpA8Q+U="},"bootstrap/glyphicons-halflings-regular-e395044093757d82afcb138957d06a1ea9361bdcf0b442d06a18a8051af57456.ttf":{"logical_path":"bootstrap/glyphicons-halflings-regular.ttf","mtime":"2015-10-19T13:57:56+03:00","size":45404,"digest":"e395044093757d82afcb138957d06a1ea9361bdcf0b442d06a18a8051af57456","integrity":"sha256-45UEQJN1fYKvyxOJV9BqHqk2G9zwtELQahioBRr1dFY="},"bootstrap/glyphicons-halflings-regular-a26394f7ede100ca118eff2eda08596275a9839b959c226e15439557a5a80742.woff":{"logical_path":"bootstrap/glyphicons-halflings-regular.woff","mtime":"2015-10-19T13:57:56+03:00","size":23424,"digest":"a26394f7ede100ca118eff2eda08596275a9839b959c226e15439557a5a80742","integrity":"sha256-omOU9+3hAMoRjv8u2ghZYnWpg5uVnCJuFUOVV6WoB0I="},"bootstrap/glyphicons-halflings-regular-fe185d11a49676890d47bb783312a0cda5a44c4039214094e7957b4c040ef11c.woff2":{"logical_path":"bootstrap/glyphicons-halflings-regular.woff2","mtime":"2015-10-19T13:57:56+03:00","size":18028,"digest":"fe185d11a49676890d47bb783312a0cda5a44c4039214094e7957b4c040ef11c","integrity":"sha256-/hhdEaSWdokNR7t4MxKgzaWkTEA5IUCU55V7TAQO8Rw="},"admin-manifest-1b7a9adf38de3299af2f97b0c037bf01c21b7056910e5ee41507a91ab675bd4d.css":{"logical_path":"admin-manifest.css","mtime":"2015-06-16T16:19:54+03:00","size":163910,"digest":"1b7a9adf38de3299af2f97b0c037bf01c21b7056910e5ee41507a91ab675bd4d","integrity":"sha256-G3qa3zjeMpmvL5ewwDe/AcIbcFaRDl7kFQepGrZ1vU0="},"admin-manifest-5f612f59c9effcca0be5396c4f00654de236d2bb1b16bbdf929b47e6504381f3.js":{"logical_path":"admin-manifest.js","mtime":"2015-06-08T14:38:06+03:00","size":323893,"digest":"5f612f59c9effcca0be5396c4f00654de236d2bb1b16bbdf929b47e6504381f3","integrity":"sha256-X2EvWcnv/MoL5TlsTwBlTeI20rsbFrvfkptH5lBDgfM="},"registrar-manifest-b4694748846de7a7f12463c4524f71013645b58fc770188432dfc5c5a93ded3a.css":{"logical_path":"registrar-manifest.css","mtime":"2015-06-16T16:19:54+03:00","size":187703,"digest":"b4694748846de7a7f12463c4524f71013645b58fc770188432dfc5c5a93ded3a","integrity":"sha256-tGlHSIRt56fxJGPEUk9xATZFtY/HcBiEMt/Fxak97To="},"registrar-manifest-700f689d9abdd73516260d2622b912a8d3e003de966996ba7a331bfa065720e7.js":{"logical_path":"registrar-manifest.js","mtime":"2015-06-19T15:29:08+03:00","size":314928,"digest":"700f689d9abdd73516260d2622b912a8d3e003de966996ba7a331bfa065720e7","integrity":"sha256-cA9onZq91zUWJg0mIrkSqNPgA96WaZa6ejMb+gZXIOc="},"registrant-manifest-ffb2502ddd176bf6bf64424abdf509f1c2fa44883cd159ffc6e0bf5bba81a226.css":{"logical_path":"registrant-manifest.css","mtime":"2015-06-16T16:19:54+03:00","size":187888,"digest":"ffb2502ddd176bf6bf64424abdf509f1c2fa44883cd159ffc6e0bf5bba81a226","integrity":"sha256-/7JQLd0Xa/a/ZEJKvfUJ8cL6RIg80Vn/xuC/W7qBoiY="},"registrant-manifest-700f689d9abdd73516260d2622b912a8d3e003de966996ba7a331bfa065720e7.js":{"logical_path":"registrant-manifest.js","mtime":"2015-06-19T15:29:08+03:00","size":314928,"digest":"700f689d9abdd73516260d2622b912a8d3e003de966996ba7a331bfa065720e7","integrity":"sha256-cA9onZq91zUWJg0mIrkSqNPgA96WaZa6ejMb+gZXIOc="},"shared/pdf-8d8bf4207c64d5de1ad8a683ed3c0d97dbe85a73644e9440b3a7c1d638c93590.css":{"logical_path":"shared/pdf.css","mtime":"2015-05-15T15:29:32+03:00","size":119782,"digest":"8d8bf4207c64d5de1ad8a683ed3c0d97dbe85a73644e9440b3a7c1d638c93590","integrity":"sha256-jYv0IHxk1d4a2KaD7TwNl9voWnNkTpRAs6fB1jjJNZA="},"admin/application-2e4aafc94dbce8d43d7bac4eb5521a14a72e3bbeece3b4363494d70fcd274542.js":{"logical_path":"admin/application.js","mtime":"2015-06-08T11:23:15+03:00","size":287,"digest":"2e4aafc94dbce8d43d7bac4eb5521a14a72e3bbeece3b4363494d70fcd274542","integrity":"sha256-LkqvyU286NQ9e6xOtVIaFKcuO77s47Q2NJTXD80nRUI="},"registrar/application-f96ff2f3f4d2326db627c9191074e5c10ad3679eac8eb2d22e3a9faef39e06a9.js":{"logical_path":"registrar/application.js","mtime":"2015-06-19T15:29:08+03:00","size":826,"digest":"f96ff2f3f4d2326db627c9191074e5c10ad3679eac8eb2d22e3a9faef39e06a9","integrity":"sha256-+W/y8/TSMm22J8kZEHTlwQrTZ56sjrLSLjqfrvOeBqk="},"registrar-manifest-413fda057832b25dee9d45f5f07b29ac369fc85f51ecd9e7bc2cdefa5297b4f3.js":{"logical_path":"registrar-manifest.js","mtime":"2015-06-08T14:38:06+03:00","size":314906,"digest":"413fda057832b25dee9d45f5f07b29ac369fc85f51ecd9e7bc2cdefa5297b4f3","integrity":"sha256-QT/aBXgysl3unUX18HsprDafyF9R7NnnvCze+lKXtPM="},"registrant-manifest-f9e9d795de4f7dabe387365fd329c1cb24da923bd357988c120cc5710230cc48.js":{"logical_path":"registrant-manifest.js","mtime":"2015-06-08T14:38:06+03:00","size":314906,"digest":"f9e9d795de4f7dabe387365fd329c1cb24da923bd357988c120cc5710230cc48","integrity":"sha256-+enXld5PfavjhzZf0ynByyTakjvTV5iMEgzFcQIwzEg="},"registrar/application-978b21a99ae3caabb8a9e301dccaa0b93f86cc789a9595158c98ee51393b8cb9.js":{"logical_path":"registrar/application.js","mtime":"2015-06-19T16:03:53+03:00","size":804,"digest":"978b21a99ae3caabb8a9e301dccaa0b93f86cc789a9595158c98ee51393b8cb9","integrity":"sha256-l4shqZrjyqu4qeMB3MqguT+GzHialZUVjJjuUTk7jLk="},"admin-manifest-6e5e54ad9b1f48eb4372bf4d3ffd1854d859dc5e2ab4977dbf59c4abfeebd760.css":{"logical_path":"admin-manifest.css","mtime":"2015-07-13T18:30:38+03:00","size":169226,"digest":"6e5e54ad9b1f48eb4372bf4d3ffd1854d859dc5e2ab4977dbf59c4abfeebd760","integrity":"sha256-bl5UrZsfSOtDcr9NP/0YVNhZ3F4qtJd9v1nEq/7r12A="},"admin-manifest-b904d5679d9ed357c2412b8d9054c5d60b6c8524e11e4ff80d2e45580108e709.js":{"logical_path":"admin-manifest.js","mtime":"2015-07-13T18:30:38+03:00","size":325028,"digest":"b904d5679d9ed357c2412b8d9054c5d60b6c8524e11e4ff80d2e45580108e709","integrity":"sha256-uQTVZ52e01fCQSuNkFTF1gtshSThHk/4DS5FWAEI5wk="},"registrar-manifest-d9e1a3fb37873e44c313486ea2ad7ff1791e9ce4d6d44e95a602d87d480f27e1.css":{"logical_path":"registrar-manifest.css","mtime":"2015-07-13T18:30:38+03:00","size":193019,"digest":"d9e1a3fb37873e44c313486ea2ad7ff1791e9ce4d6d44e95a602d87d480f27e1","integrity":"sha256-2eGj+zeHPkTDE0huoq1/8XkenOTW1E6VpgLYfUgPJ+E="},"registrar-manifest-0297caa2939148f9284b754e7a0cc2a08272b8ff3194d97be0c95858498cbe39.js":{"logical_path":"registrar-manifest.js","mtime":"2015-07-13T18:30:38+03:00","size":316041,"digest":"0297caa2939148f9284b754e7a0cc2a08272b8ff3194d97be0c95858498cbe39","integrity":"sha256-ApfKopORSPkoS3VOegzCoIJyuP8xlNl74MlYWEmMvjk="},"registrant-manifest-651e30954782cb9b1e582abeb18c47402c951e3fd4aa71311363a058869f4d66.css":{"logical_path":"registrant-manifest.css","mtime":"2015-07-13T18:30:38+03:00","size":193204,"digest":"651e30954782cb9b1e582abeb18c47402c951e3fd4aa71311363a058869f4d66","integrity":"sha256-ZR4wlUeCy5seWCq+sYxHQCyVHj/UqnExE2OgWIafTWY="},"registrant-manifest-a94cc4d69bafc048f1cb08fffd1c733fc37157e660e4897005207cf03f1d98ca.js":{"logical_path":"registrant-manifest.js","mtime":"2015-07-13T18:30:38+03:00","size":316041,"digest":"a94cc4d69bafc048f1cb08fffd1c733fc37157e660e4897005207cf03f1d98ca","integrity":"sha256-qUzE1puvwEjxywj//RxzP8NxV+Zg5IlwBSB88D8dmMo="},"shared/pdf-3f6858cfb5eec601002c5a418b287ccdddf38bb953111ffdff1321d3b1fbbddc.css":{"logical_path":"shared/pdf.css","mtime":"2015-06-29T12:04:56+03:00","size":125098,"digest":"3f6858cfb5eec601002c5a418b287ccdddf38bb953111ffdff1321d3b1fbbddc","integrity":"sha256-P2hYz7XuxgEALFpBiyh8zd3zi7lTER/9/xMh07H7vdw="},"admin-manifest-7058b706893af7473775946fa6171e3c3d7d81f5fe323c402acc8b207eac4f1b.css":{"logical_path":"admin-manifest.css","mtime":"2015-07-22T12:51:15+03:00","size":169258,"digest":"7058b706893af7473775946fa6171e3c3d7d81f5fe323c402acc8b207eac4f1b","integrity":"sha256-cFi3Bok690c3dZRvphcePD19gfX+MjxAKsyLIH6sTxs="},"registrar-manifest-12ddf3d27aeb82ed229b8a7ec6b50fdfa33c115326bb540d3c64d630122382bb.css":{"logical_path":"registrar-manifest.css","mtime":"2015-07-30T17:08:04+03:00","size":193051,"digest":"12ddf3d27aeb82ed229b8a7ec6b50fdfa33c115326bb540d3c64d630122382bb","integrity":"sha256-Et3z0nrrgu0im4p+xrUP36M8EVMmu1QNPGTWMBIjgrs="},"registrant-manifest-9711ccec91402d435ddfb0b0fbf708a1ffef67868a86c38014f975183d61e324.css":{"logical_path":"registrant-manifest.css","mtime":"2015-07-30T17:08:04+03:00","size":193236,"digest":"9711ccec91402d435ddfb0b0fbf708a1ffef67868a86c38014f975183d61e324","integrity":"sha256-lxHM7JFALUNd37Cw+/cIof/vZ4aKhsOAFPl1GD1h4yQ="},"admin-manifest-8e7ee8a12ecba21371b22a0f225d918c48c4edb92c4e793c76bcbc85f1d11b2d.js":{"logical_path":"admin-manifest.js","mtime":"2015-07-29T11:55:32+03:00","size":325018,"digest":"8e7ee8a12ecba21371b22a0f225d918c48c4edb92c4e793c76bcbc85f1d11b2d","integrity":"sha256-jn7ooS7LohNxsioPIl2RjEjE7bksTnk8dry8hfHRGy0="},"registrar-manifest-ccfec673488bbf1709b257f959ddaba3153692cd4ed34f7c10617e7cb8079c7f.js":{"logical_path":"registrar-manifest.js","mtime":"2015-07-29T11:55:32+03:00","size":316031,"digest":"ccfec673488bbf1709b257f959ddaba3153692cd4ed34f7c10617e7cb8079c7f","integrity":"sha256-zP7Gc0iLvxcJslf5Wd2roxU2ks1O0098EGF+fLgHnH8="},"registrant-manifest-029b3513f5314789848386b24148311e44df8160a0a4b5b587a6e6a446eddd45.js":{"logical_path":"registrant-manifest.js","mtime":"2015-07-29T11:55:32+03:00","size":316031,"digest":"029b3513f5314789848386b24148311e44df8160a0a4b5b587a6e6a446eddd45","integrity":"sha256-Aps1E/UxR4mEg4ayQUgxHkTfgWCgpLW1h6bmpEbt3UU="},"admin-manifest-faacc44f2693434d482abfa34e565890367f8a34a73a4334fb690dfd36606599.css":{"logical_path":"admin-manifest.css","mtime":"2015-07-30T17:08:04+03:00","size":195931,"digest":"faacc44f2693434d482abfa34e565890367f8a34a73a4334fb690dfd36606599","integrity":"sha256-+qzETyaTQ01IKr+jTlZYkDZ/ijSnOkM0+2kN/TZgZZk="},"admin-manifest-2d50db228bce0154b10046fa6de58775cf879387a8a2e63e278e51ef7802ddba.js":{"logical_path":"admin-manifest.js","mtime":"2015-07-30T17:08:04+03:00","size":391499,"digest":"2d50db228bce0154b10046fa6de58775cf879387a8a2e63e278e51ef7802ddba","integrity":"sha256-LVDbIovOAVSxAEb6beWHdc+Hk4eoouY+J45R73gC3bo="},"registrar-manifest-acc585f0f8ccb8f3a1b2ba4f54b847d34f588c8fcefc055a29cb89dc3045279e.js":{"logical_path":"registrar-manifest.js","mtime":"2015-08-11T16:52:25+03:00","size":360581,"digest":"acc585f0f8ccb8f3a1b2ba4f54b847d34f588c8fcefc055a29cb89dc3045279e","integrity":"sha256-rMWF8PjMuPOhsrpPVLhH009YjI/O/AVaKcuJ3DBFJ54="},"registrar-manifest-9bc7e99a627bcd8cd851f05e1595592ba458671ccd1fb663f500229671eb30c9.js":{"logical_path":"registrar-manifest.js","mtime":"2015-08-11T17:07:57+03:00","size":316080,"digest":"9bc7e99a627bcd8cd851f05e1595592ba458671ccd1fb663f500229671eb30c9","integrity":"sha256-m8fpmmJ7zYzYUfBeFZVZK6RYZxzNH7Zj9QAilnHrMMk="},"registrant-manifest-9bc7e99a627bcd8cd851f05e1595592ba458671ccd1fb663f500229671eb30c9.js":{"logical_path":"registrant-manifest.js","mtime":"2015-08-11T16:54:20+03:00","size":316080,"digest":"9bc7e99a627bcd8cd851f05e1595592ba458671ccd1fb663f500229671eb30c9","integrity":"sha256-m8fpmmJ7zYzYUfBeFZVZK6RYZxzNH7Zj9QAilnHrMMk="},"registrar/application-d550a9694cdd4555f5ebaa3317954f548b4a9109e33e4c81ecfeb386ae70eed6.js":{"logical_path":"registrar/application.js","mtime":"2015-08-11T16:54:20+03:00","size":853,"digest":"d550a9694cdd4555f5ebaa3317954f548b4a9109e33e4c81ecfeb386ae70eed6","integrity":"sha256-1VCpaUzdRVX166ozF5VPVItKkQnjPkyB7P6zhq5w7tY="},"admin-manifest-5729e7fb1a7bc14e9eecd448e5809449b2f9df89194aa3fef831b9affb96b005.js":{"logical_path":"admin-manifest.js","mtime":"2015-08-14T14:24:10+03:00","size":391663,"digest":"5729e7fb1a7bc14e9eecd448e5809449b2f9df89194aa3fef831b9affb96b005","integrity":"sha256-Vynn+xp7wU6e7NRI5YCUSbL534kZSqP++DG5r/uWsAU="},"registrar-manifest-e978136c269d5727a484c9fe6b6feaf6be7a29cf8fc8605f397bdad192bb5e38.js":{"logical_path":"registrar-manifest.js","mtime":"2015-08-14T14:24:10+03:00","size":316195,"digest":"e978136c269d5727a484c9fe6b6feaf6be7a29cf8fc8605f397bdad192bb5e38","integrity":"sha256-6XgTbCadVyekhMn+a2/q9r56Kc+PyGBfOXva0ZK7Xjg="},"registrant-manifest-a2003d1a69b4bdf015c46964954aacf8be29f409e1a79d7d9d0b8d75244179ce.js":{"logical_path":"registrant-manifest.js","mtime":"2015-08-14T14:24:10+03:00","size":316195,"digest":"a2003d1a69b4bdf015c46964954aacf8be29f409e1a79d7d9d0b8d75244179ce","integrity":"sha256-ogA9Gmm0vfAVxGlklUqs+L4p9Anhp519nQuNdSRBec4="},"admin-manifest-bcf3c4cef0117f21acb70a7c9b5f06f25d057eda308dd9839ae76eee4b618e58.css":{"logical_path":"admin-manifest.css","mtime":"2015-09-25T11:45:47+03:00","size":492663,"digest":"bcf3c4cef0117f21acb70a7c9b5f06f25d057eda308dd9839ae76eee4b618e58","integrity":"sha256-vPPEzvARfyGstwp8m18G8l0FftowjdmDmudu7kthjlg="},"admin-manifest-b56c888710b293cd3d8331ab98c3132ab94673b812821996e8229d523520b97e.js":{"logical_path":"admin-manifest.js","mtime":"2015-10-28T08:41:33+02:00","size":862756,"digest":"b56c888710b293cd3d8331ab98c3132ab94673b812821996e8229d523520b97e","integrity":"sha256-tWyIhxCyk809gzGrmMMTKrlGc7gSghmW6CKdUjUguX4="},"registrar-manifest-e364a56d5bdb750496486844d792a5f4782d00428c349d0cf1784c81b6d41b04.css":{"logical_path":"registrar-manifest.css","mtime":"2015-09-25T11:45:47+03:00","size":484790,"digest":"e364a56d5bdb750496486844d792a5f4782d00428c349d0cf1784c81b6d41b04","integrity":"sha256-42SlbVvbdQSWSGhE15Kl9HgtAEKMNJ0M8XhMgbbUGwQ="},"registrar-manifest-923bdd894c37c44dd7b0f023e75e83c272cb3661a43d8a9de1b5f064d56e9a6f.js":{"logical_path":"registrar-manifest.js","mtime":"2015-09-25T11:45:47+03:00","size":732381,"digest":"923bdd894c37c44dd7b0f023e75e83c272cb3661a43d8a9de1b5f064d56e9a6f","integrity":"sha256-kjvdiUw3xE3XsPAj516DwnLLNmGkPYqd4bXwZNVumm8="},"registrant-manifest-d47a96d48f8ec37e21e16198a53f282561ce6503baa9eb08b2194bc06230f9d8.css":{"logical_path":"registrant-manifest.css","mtime":"2015-09-25T11:45:47+03:00","size":485322,"digest":"d47a96d48f8ec37e21e16198a53f282561ce6503baa9eb08b2194bc06230f9d8","integrity":"sha256-1HqW1I+Ow34h4WGYpT8oJWHOZQO6qesIshlLwGIw+dg="},"registrant-manifest-923bdd894c37c44dd7b0f023e75e83c272cb3661a43d8a9de1b5f064d56e9a6f.js":{"logical_path":"registrant-manifest.js","mtime":"2015-10-22T12:10:32+03:00","size":732381,"digest":"923bdd894c37c44dd7b0f023e75e83c272cb3661a43d8a9de1b5f064d56e9a6f","integrity":"sha256-kjvdiUw3xE3XsPAj516DwnLLNmGkPYqd4bXwZNVumm8="},"shared/pdf-d666bc3228e9a0994a2cc4dfc95ec2863ceb26da94735fb9b89c7b57ad513f4a.css":{"logical_path":"shared/pdf.css","mtime":"2015-06-29T12:04:56+03:00","size":362054,"digest":"d666bc3228e9a0994a2cc4dfc95ec2863ceb26da94735fb9b89c7b57ad513f4a","integrity":"sha256-1ma8MijpoJlKLMTfyV7ChjzrJtqUc1+5uJx7V61RP0o="},"admin/application-af4a49d884fc4a80976a01b28e2db12db7319d5bdf6288f069aa694e99dcbfb9.js":{"logical_path":"admin/application.js","mtime":"2015-10-28T08:41:33+02:00","size":440,"digest":"af4a49d884fc4a80976a01b28e2db12db7319d5bdf6288f069aa694e99dcbfb9","integrity":"sha256-r0pJ2IT8SoCXagGyji2xLbcxnVvfYojwaappTpncv7k="},"registrar/application-491270943cec365218178f37d9682c9ff4e9876669baab774edd46e4dd90ba0b.js":{"logical_path":"registrar/application.js","mtime":"2015-10-06T14:16:22+03:00","size":1080,"digest":"491270943cec365218178f37d9682c9ff4e9876669baab774edd46e4dd90ba0b","integrity":"sha256-SRJwlDzsNlIYF4832Wgsn/Tph2Zpuqt3Tt1G5N2Qugs="},"eis_logo_rgb_block-5be8e7be99ea89a55b7cec036d687132fb5aab58fa63130418ac849661b5466e.png":{"logical_path":"eis_logo_rgb_block.png","mtime":"2015-09-24T11:06:54+03:00","size":27796,"digest":"5be8e7be99ea89a55b7cec036d687132fb5aab58fa63130418ac849661b5466e","integrity":"sha256-W+jnvpnqiaVbfOwDbWhxMvtaq1j6YxMEGKyElmG1Rm4="},"admin-manifest-495df56cbf98a3f293ec0da2cc4b66358fde29989e7fe9ec6650bdeba096d041.css":{"logical_path":"admin-manifest.css","mtime":"2015-10-22T08:10:29+03:00","size":478837,"digest":"495df56cbf98a3f293ec0da2cc4b66358fde29989e7fe9ec6650bdeba096d041","integrity":"sha256-SV31bL+Yo/KT7A2izEtmNY/eKZief+nsZlC966CW0EE="},"registrar-manifest-2a97c9dddb568c2931f3fc6cf42ecd44d8900db37c207a41b24e16966b647384.css":{"logical_path":"registrar-manifest.css","mtime":"2015-10-22T08:05:44+03:00","size":470414,"digest":"2a97c9dddb568c2931f3fc6cf42ecd44d8900db37c207a41b24e16966b647384","integrity":"sha256-KpfJ3dtWjCkx8/xs9C7NRNiQDbN8IHpBsk4Wlmtkc4Q="},"registrar-manifest-f12fa4f2e8834d80e063f5da710b23ca70686c43f0b16e8b1e5505d686188ad8.js":{"logical_path":"registrar-manifest.js","mtime":"2015-10-22T09:47:03+03:00","size":763265,"digest":"f12fa4f2e8834d80e063f5da710b23ca70686c43f0b16e8b1e5505d686188ad8","integrity":"sha256-8S+k8uiDTYDgY/XacQsjynBobEPwsW6LHlUF1oYYitg="},"registrant-manifest-20a40540018cb3ef7671ab4eb5c421318ea6e606e8ae11d5e6c54cc8273271d9.css":{"logical_path":"registrant-manifest.css","mtime":"2015-10-22T12:10:32+03:00","size":470979,"digest":"20a40540018cb3ef7671ab4eb5c421318ea6e606e8ae11d5e6c54cc8273271d9","integrity":"sha256-IKQFQAGMs+92catOtcQhMY6m5gborhHV5sVMyCcycdk="},"shared/pdf-8b025919dfa001504fb3a7ab72fe8b7666c7492bf92955510ab68248fb499f53.css":{"logical_path":"shared/pdf.css","mtime":"2015-10-19T13:57:56+03:00","size":349048,"digest":"8b025919dfa001504fb3a7ab72fe8b7666c7492bf92955510ab68248fb499f53","integrity":"sha256-iwJZGd+gAVBPs6ercv6LdmbHSSv5KVVRCraCSPtJn1M="}},"assets":{"admin-manifest.css":"admin-manifest-495df56cbf98a3f293ec0da2cc4b66358fde29989e7fe9ec6650bdeba096d041.css","admin-manifest.js":"admin-manifest-b56c888710b293cd3d8331ab98c3132ab94673b812821996e8229d523520b97e.js","registrar-manifest.css":"registrar-manifest-2a97c9dddb568c2931f3fc6cf42ecd44d8900db37c207a41b24e16966b647384.css","registrar-manifest.js":"registrar-manifest-f12fa4f2e8834d80e063f5da710b23ca70686c43f0b16e8b1e5505d686188ad8.js","registrant-manifest.css":"registrant-manifest-20a40540018cb3ef7671ab4eb5c421318ea6e606e8ae11d5e6c54cc8273271d9.css","registrant-manifest.js":"registrant-manifest-923bdd894c37c44dd7b0f023e75e83c272cb3661a43d8a9de1b5f064d56e9a6f.js","shared/pdf.css":"shared/pdf-8b025919dfa001504fb3a7ab72fe8b7666c7492bf92955510ab68248fb499f53.css","select2.png":"select2-d6b5d8d83dbc18fb8d77c8761d331cd9e5123c9684950bab0406e98a24ac5ae8.png","select2-spinner.gif":"select2-spinner-f6ecff617ec2ba7f559e6f535cad9b70a3f91120737535dab4d4548a6c83576c.gif","select2x2.png":"select2x2-6fe28d687dc0ed4d96016238c608ba1e7198c9c9accfa0b360b78018b9fb9bc2.png","alpha.png":"alpha-9ac45a6b3c13dd5c5cf1b5d18c6f24a537dd2e4598238527d232a3e2ea5b5947.png","bg.jpg":"bg-b8036abd2f0f36e3ab54d5d5b25b0fbac11d63ec6106d959df3fa180b379de05.jpg","danske.png":"danske-07a4395cc406785da129414e15872fe1d6a4f6f6da0066da6701b56cdb72ea96.png","development.png":"development-0b993e22410c7952394ac19ce3b41b722a97b93138a9a002091e1e5226d29bf5.png","eis-logo-et.png":"eis-logo-et-86a549d266cda73e3225c5eeba14532c59d498e1fd980ec129fded68da8bb307.png","favicon.ico":"favicon-309e00e2f78f9a2b042abc2806a8a4ed9cf6bb5d3f00ccc0985b1308bfd86c49.ico","id_card.gif":"id_card-ea506a49b25c8de4e68e786d90f5ec5defb6c8e895b90f2f129815f5e550fe8e.gif","lhv.png":"lhv-4d09d3126a05df392b73c54fa9b1eb605798c2e9bd361cf44500f73038832030.png","mid.gif":"mid-275543ecea377debe1ac892470f3aea4f7e7f0f9089fc0fbea4de410742e5239.gif","nordea.png":"nordea-75c938c7436e0c8316f056be8df8acd0e8b16e09790e78f78da96d9f8633ef3b.png","registrar/bg-alpha.png":"registrar/bg-alpha-9ac45a6b3c13dd5c5cf1b5d18c6f24a537dd2e4598238527d232a3e2ea5b5947.png","registrar/bg-development.png":"registrar/bg-development-0b993e22410c7952394ac19ce3b41b722a97b93138a9a002091e1e5226d29bf5.png","registrar/bg-staging.png":"registrar/bg-staging-6276f8c00911bc99f301f919e408ae3ef726c7378324ac55fd5d378ba3a4dc2d.png","registrar/favicon.ico":"registrar/favicon-e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.ico","seb.png":"seb-9c9d943014cc4ee706244893cd8a2c4a8a7cc97bfbdef6a66e22c72f33d5f25e.png","staging.png":"staging-6276f8c00911bc99f301f919e408ae3ef726c7378324ac55fd5d378ba3a4dc2d.png","swed.png":"swed-2cf45729062cf5fa634247ba372c579c97f382e5cc43fa111219077e7473fdbb.png","test.png":"test-9ac45a6b3c13dd5c5cf1b5d18c6f24a537dd2e4598238527d232a3e2ea5b5947.png","admin/application.js":"admin/application-af4a49d884fc4a80976a01b28e2db12db7319d5bdf6288f069aa694e99dcbfb9.js","registrar/application.js":"registrar/application-491270943cec365218178f37d9682c9ff4e9876669baab774edd46e4dd90ba0b.js","etelkalight-webfont.eot":"etelkalight-webfont-baf7e35ab2f64bf1c6fa4476d3934c7422062995738fd9e5715b02f55002d7c0.eot","etelkalight-webfont.svg":"etelkalight-webfont-2b575f6e4696d74957af27a7c7bb7976b7ca31d0ebe8ec25bb4c3494d5d16e24.svg","etelkalight-webfont.ttf":"etelkalight-webfont-f68a2db6346d864f82c3b3e725ee60b0217e91e46ec47f96710f70f996b61af1.ttf","etelkalight-webfont.woff":"etelkalight-webfont-1ed38dbac6b817bf74bd46a98d61005aa2615db7ac743e4037364d1021084043.woff","etelkalightbold-webfont.eot":"etelkalightbold-webfont-1d94cabe6fb55b05f746fe0aa51a7a503683d7afdb68360ed26bfac03e1b3c39.eot","etelkalightbold-webfont.svg":"etelkalightbold-webfont-bb0c8e17b99b10f211be3531a51d6ad48a5c6e4670c8fb6160a329fa4758c555.svg","etelkalightbold-webfont.ttf":"etelkalightbold-webfont-0f06d1e7f099578e1cc0e9b1875aca2a7128c0ca0d640fd504e97bae0b028429.ttf","etelkalightbold-webfont.woff":"etelkalightbold-webfont-d608c036b3e3f04ca87a1c494f8d9e9620a729b2760b5eb1dcee52c4bc8e8805.woff","etelkalightitalic-webfont.eot":"etelkalightitalic-webfont-ce5cdffe6c589a6dc6bd2c482c718486ff5fb416ab01740750db325179e58654.eot","etelkalightitalic-webfont.svg":"etelkalightitalic-webfont-dd5353c2af4ea63e1d0e99ec5f1f85162cee0c4dd0a3840260a2606eefc3e517.svg","etelkalightitalic-webfont.ttf":"etelkalightitalic-webfont-54eb91ad0e0b639f50be02b7c25836c99ad989185f5d2a240d60ea14a1b7384a.ttf","etelkalightitalic-webfont.woff":"etelkalightitalic-webfont-d1fb9621d40ef45104078a4a5b98ce4cba00872cf8ac56e299cf1397c146cac3.woff","infotexb-webfont.eot":"infotexb-webfont-1951e43e1d9ab99b0d4998abba4aab34f3e68b337be90800db517e4a8d27d001.eot","infotexb-webfont.svg":"infotexb-webfont-0dda72e34d0d0ced7693b55ed08acc60fb1a9036afd7736e432ac3f22f2e6fdf.svg","infotexb-webfont.ttf":"infotexb-webfont-c0737d1e2edff50645e201bf99f68f2313502ee2bdeb2e56435ee24721baf5cd.ttf","infotexb-webfont.woff":"infotexb-webfont-8da32e6db23c39390c55dd5ea8949714757fddba516c5db65e72867504493fbc.woff","infotexm-webfont.eot":"infotexm-webfont-74df99faeb66d8b02966b8884b860af03c359ed41d348ddb813dbcc3c460eb26.eot","infotexm-webfont.svg":"infotexm-webfont-0b52ef10620b8cb7289dc809aac67826d5031e6ab040194fdb7365dc83e95557.svg","infotexm-webfont.ttf":"infotexm-webfont-1d244d27a4ec4c1a5f98c82966faa26e7855c4292c730429477003b6dab5c08b.ttf","infotexm-webfont.woff":"infotexm-webfont-872b5ab4e0b7de6655a52f137a3c99f1e7941fa91ff21a56550f2039834ee9d0.woff","jquery-ui/ui-bg_flat_0_aaaaaa_40x100.png":"jquery-ui/ui-bg_flat_0_aaaaaa_40x100-9a8492a580bf85d3e98ae8861fbd45567e5a1f83eeafcf9574da0399d5f602ab.png","jquery-ui/ui-bg_flat_75_ffffff_40x100.png":"jquery-ui/ui-bg_flat_75_ffffff_40x100-39ab7ccd9f4e82579da78a9241265df288d8eb65dbbd7cf48aed2d0129887df5.png","jquery-ui/ui-bg_glass_55_fbf9ee_1x400.png":"jquery-ui/ui-bg_glass_55_fbf9ee_1x400-691597e8a40a891ea94d3589976ecfc33e6145c49422443b00ac2b5a0022964c.png","jquery-ui/ui-bg_glass_65_ffffff_1x400.png":"jquery-ui/ui-bg_glass_65_ffffff_1x400-f0e6cd91b837d5c5644d026e5ffeccd907953317cd5c0f689901733afda260b2.png","jquery-ui/ui-bg_glass_75_dadada_1x400.png":"jquery-ui/ui-bg_glass_75_dadada_1x400-c108f5cbf2dd9ec07a26530695ddd95e1664597ce6c056ae44c162cc2e28cec4.png","jquery-ui/ui-bg_glass_75_e6e6e6_1x400.png":"jquery-ui/ui-bg_glass_75_e6e6e6_1x400-ddf5dd4e0ef2b185e8bb0af7b6e90ebe74a84384cb4700658e76e754c8bfe550.png","jquery-ui/ui-bg_glass_95_fef1ec_1x400.png":"jquery-ui/ui-bg_glass_95_fef1ec_1x400-f6f1c1bedf1a0f37cfef81d12f5f012869d1ee7c984775a569827a1784d34f5c.png","jquery-ui/ui-bg_highlight-soft_75_cccccc_1x100.png":"jquery-ui/ui-bg_highlight-soft_75_cccccc_1x100-54270656df079c4da5182629a080fc633b6f84b87985eb016d25a560e2c38d4a.png","jquery-ui/ui-icons_222222_256x240.png":"jquery-ui/ui-icons_222222_256x240-57adb0d65f4e91dacfee975d9574422bee7486c8a182d60133728c672f2cdbbc.png","jquery-ui/ui-icons_2e83ff_256x240.png":"jquery-ui/ui-icons_2e83ff_256x240-20f8c6667afc48aa433ee9eb6d8a0584bdbd6b4a4a9091ff1e6b3adb31e63bd9.png","jquery-ui/ui-icons_454545_256x240.png":"jquery-ui/ui-icons_454545_256x240-07460e843c3e59aaadbb34231e699e856a2980753c7a47b66447da5d9f93fb7f.png","jquery-ui/ui-icons_888888_256x240.png":"jquery-ui/ui-icons_888888_256x240-ea2e29625de3463465e93b002b065f5833e05b97f7a052b1c141e754d62e1a8b.png","jquery-ui/ui-icons_cd0a0a_256x240.png":"jquery-ui/ui-icons_cd0a0a_256x240-1e32c6dbf5d3fd342f27a78aa881550d6412aa207f48468724a6a15402b6041b.png","bootstrap/glyphicons-halflings-regular.eot":"bootstrap/glyphicons-halflings-regular-13634da87d9e23f8c3ed9108ce1724d183a39ad072e73e1b3d8cbf646d2d0407.eot","bootstrap/glyphicons-halflings-regular.svg":"bootstrap/glyphicons-halflings-regular-42f60659d265c1a3c30f9fa42abcbb56bd4a53af4d83d316d6dd7a36903c43e5.svg","bootstrap/glyphicons-halflings-regular.ttf":"bootstrap/glyphicons-halflings-regular-e395044093757d82afcb138957d06a1ea9361bdcf0b442d06a18a8051af57456.ttf","bootstrap/glyphicons-halflings-regular.woff":"bootstrap/glyphicons-halflings-regular-a26394f7ede100ca118eff2eda08596275a9839b959c226e15439557a5a80742.woff","bootstrap/glyphicons-halflings-regular.woff2":"bootstrap/glyphicons-halflings-regular-fe185d11a49676890d47bb783312a0cda5a44c4039214094e7957b4c040ef11c.woff2","eis_logo_rgb_block.png":"eis_logo_rgb_block-5be8e7be99ea89a55b7cec036d687132fb5aab58fa63130418ac849661b5466e.png"}} \ No newline at end of file diff --git a/public/assets/admin-manifest-025801216a3b153631239205b373c5e4ac42d55cc9a53960d3c485b5eed9d467.js b/public/assets/admin-manifest-025801216a3b153631239205b373c5e4ac42d55cc9a53960d3c485b5eed9d467.js deleted file mode 100644 index fc81fe2ec..000000000 --- a/public/assets/admin-manifest-025801216a3b153631239205b373c5e4ac42d55cc9a53960d3c485b5eed9d467.js +++ /dev/null @@ -1,23228 +0,0 @@ -/*! - * jQuery JavaScript Library v1.11.2 - * http://jquery.com/ - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * - * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors - * Released under the MIT license - * http://jquery.org/license - * - * Date: 2014-12-17T15:27Z - */ - - -(function( global, factory ) { - - if ( typeof module === "object" && typeof module.exports === "object" ) { - // For CommonJS and CommonJS-like environments where a proper window is present, - // execute the factory and get jQuery - // For environments that do not inherently posses a window with a document - // (such as Node.js), expose a jQuery-making factory as module.exports - // This accentuates the need for the creation of a real window - // e.g. var jQuery = require("jquery")(window); - // See ticket #14549 for more info - module.exports = global.document ? - factory( global, true ) : - function( w ) { - if ( !w.document ) { - throw new Error( "jQuery requires a window with a document" ); - } - return factory( w ); - }; - } else { - factory( global ); - } - -// Pass this if window is not defined yet -}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) { - -// Can't do this because several apps including ASP.NET trace -// the stack via arguments.caller.callee and Firefox dies if -// you try to trace through "use strict" call chains. (#13335) -// Support: Firefox 18+ -// - -var deletedIds = []; - -var slice = deletedIds.slice; - -var concat = deletedIds.concat; - -var push = deletedIds.push; - -var indexOf = deletedIds.indexOf; - -var class2type = {}; - -var toString = class2type.toString; - -var hasOwn = class2type.hasOwnProperty; - -var support = {}; - - - -var - version = "1.11.2", - - // Define a local copy of jQuery - jQuery = function( selector, context ) { - // The jQuery object is actually just the init constructor 'enhanced' - // Need init if jQuery is called (just allow error to be thrown if not included) - return new jQuery.fn.init( selector, context ); - }, - - // Support: Android<4.1, IE<9 - // Make sure we trim BOM and NBSP - rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, - - // Matches dashed string for camelizing - rmsPrefix = /^-ms-/, - rdashAlpha = /-([\da-z])/gi, - - // Used by jQuery.camelCase as callback to replace() - fcamelCase = function( all, letter ) { - return letter.toUpperCase(); - }; - -jQuery.fn = jQuery.prototype = { - // The current version of jQuery being used - jquery: version, - - constructor: jQuery, - - // Start with an empty selector - selector: "", - - // The default length of a jQuery object is 0 - length: 0, - - toArray: function() { - return slice.call( this ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - return num != null ? - - // Return just the one element from the set - ( num < 0 ? this[ num + this.length ] : this[ num ] ) : - - // Return all the elements in a clean array - slice.call( this ); - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems ) { - - // Build a new jQuery matched element set - var ret = jQuery.merge( this.constructor(), elems ); - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - ret.context = this.context; - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - // (You can seed the arguments with an array of args, but this is - // only used internally.) - each: function( callback, args ) { - return jQuery.each( this, callback, args ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map(this, function( elem, i ) { - return callback.call( elem, i, elem ); - })); - }, - - slice: function() { - return this.pushStack( slice.apply( this, arguments ) ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - eq: function( i ) { - var len = this.length, - j = +i + ( i < 0 ? len : 0 ); - return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] ); - }, - - end: function() { - return this.prevObject || this.constructor(null); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: push, - sort: deletedIds.sort, - splice: deletedIds.splice -}; - -jQuery.extend = jQuery.fn.extend = function() { - var src, copyIsArray, copy, name, options, clone, - target = arguments[0] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - - // skip the boolean and the target - target = arguments[ i ] || {}; - i++; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !jQuery.isFunction(target) ) { - target = {}; - } - - // extend jQuery itself if only one argument is passed - if ( i === length ) { - target = this; - i--; - } - - for ( ; i < length; i++ ) { - // Only deal with non-null/undefined values - if ( (options = arguments[ i ]) != null ) { - // Extend the base object - for ( name in options ) { - src = target[ name ]; - copy = options[ name ]; - - // Prevent never-ending loop - if ( target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { - if ( copyIsArray ) { - copyIsArray = false; - clone = src && jQuery.isArray(src) ? src : []; - - } else { - clone = src && jQuery.isPlainObject(src) ? src : {}; - } - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend({ - // Unique for each copy of jQuery on the page - expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), - - // Assume jQuery is ready without the ready module - isReady: true, - - error: function( msg ) { - throw new Error( msg ); - }, - - noop: function() {}, - - // See test/unit/core.js for details concerning isFunction. - // Since version 1.3, DOM methods and functions like alert - // aren't supported. They return false on IE (#2968). - isFunction: function( obj ) { - return jQuery.type(obj) === "function"; - }, - - isArray: Array.isArray || function( obj ) { - return jQuery.type(obj) === "array"; - }, - - isWindow: function( obj ) { - /* jshint eqeqeq: false */ - return obj != null && obj == obj.window; - }, - - isNumeric: function( obj ) { - // parseFloat NaNs numeric-cast false positives (null|true|false|"") - // ...but misinterprets leading-number strings, particularly hex literals ("0x...") - // subtraction forces infinities to NaN - // adding 1 corrects loss of precision from parseFloat (#15100) - return !jQuery.isArray( obj ) && (obj - parseFloat( obj ) + 1) >= 0; - }, - - isEmptyObject: function( obj ) { - var name; - for ( name in obj ) { - return false; - } - return true; - }, - - isPlainObject: function( obj ) { - var key; - - // Must be an Object. - // Because of IE, we also have to check the presence of the constructor property. - // Make sure that DOM nodes and window objects don't pass through, as well - if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { - return false; - } - - try { - // Not own constructor property must be Object - if ( obj.constructor && - !hasOwn.call(obj, "constructor") && - !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { - return false; - } - } catch ( e ) { - // IE8,9 Will throw exceptions on certain host objects #9897 - return false; - } - - // Support: IE<9 - // Handle iteration over inherited properties before own properties. - if ( support.ownLast ) { - for ( key in obj ) { - return hasOwn.call( obj, key ); - } - } - - // Own properties are enumerated firstly, so to speed up, - // if last one is own, then all properties are own. - for ( key in obj ) {} - - return key === undefined || hasOwn.call( obj, key ); - }, - - type: function( obj ) { - if ( obj == null ) { - return obj + ""; - } - return typeof obj === "object" || typeof obj === "function" ? - class2type[ toString.call(obj) ] || "object" : - typeof obj; - }, - - // Evaluates a script in a global context - // Workarounds based on findings by Jim Driscoll - // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context - globalEval: function( data ) { - if ( data && jQuery.trim( data ) ) { - // We use execScript on Internet Explorer - // We use an anonymous function so that context is window - // rather than jQuery in Firefox - ( window.execScript || function( data ) { - window[ "eval" ].call( window, data ); - } )( data ); - } - }, - - // Convert dashed to camelCase; used by the css and data modules - // Microsoft forgot to hump their vendor prefix (#9572) - camelCase: function( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); - }, - - nodeName: function( elem, name ) { - return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); - }, - - // args is for internal usage only - each: function( obj, callback, args ) { - var value, - i = 0, - length = obj.length, - isArray = isArraylike( obj ); - - if ( args ) { - if ( isArray ) { - for ( ; i < length; i++ ) { - value = callback.apply( obj[ i ], args ); - - if ( value === false ) { - break; - } - } - } else { - for ( i in obj ) { - value = callback.apply( obj[ i ], args ); - - if ( value === false ) { - break; - } - } - } - - // A special, fast, case for the most common use of each - } else { - if ( isArray ) { - for ( ; i < length; i++ ) { - value = callback.call( obj[ i ], i, obj[ i ] ); - - if ( value === false ) { - break; - } - } - } else { - for ( i in obj ) { - value = callback.call( obj[ i ], i, obj[ i ] ); - - if ( value === false ) { - break; - } - } - } - } - - return obj; - }, - - // Support: Android<4.1, IE<9 - trim: function( text ) { - return text == null ? - "" : - ( text + "" ).replace( rtrim, "" ); - }, - - // results is for internal usage only - makeArray: function( arr, results ) { - var ret = results || []; - - if ( arr != null ) { - if ( isArraylike( Object(arr) ) ) { - jQuery.merge( ret, - typeof arr === "string" ? - [ arr ] : arr - ); - } else { - push.call( ret, arr ); - } - } - - return ret; - }, - - inArray: function( elem, arr, i ) { - var len; - - if ( arr ) { - if ( indexOf ) { - return indexOf.call( arr, elem, i ); - } - - len = arr.length; - i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; - - for ( ; i < len; i++ ) { - // Skip accessing in sparse arrays - if ( i in arr && arr[ i ] === elem ) { - return i; - } - } - } - - return -1; - }, - - merge: function( first, second ) { - var len = +second.length, - j = 0, - i = first.length; - - while ( j < len ) { - first[ i++ ] = second[ j++ ]; - } - - // Support: IE<9 - // Workaround casting of .length to NaN on otherwise arraylike objects (e.g., NodeLists) - if ( len !== len ) { - while ( second[j] !== undefined ) { - first[ i++ ] = second[ j++ ]; - } - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, invert ) { - var callbackInverse, - matches = [], - i = 0, - length = elems.length, - callbackExpect = !invert; - - // Go through the array, only saving the items - // that pass the validator function - for ( ; i < length; i++ ) { - callbackInverse = !callback( elems[ i ], i ); - if ( callbackInverse !== callbackExpect ) { - matches.push( elems[ i ] ); - } - } - - return matches; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var value, - i = 0, - length = elems.length, - isArray = isArraylike( elems ), - ret = []; - - // Go through the array, translating each of the items to their new values - if ( isArray ) { - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - - // Go through every key on the object, - } else { - for ( i in elems ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - } - - // Flatten any nested arrays - return concat.apply( [], ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // Bind a function to a context, optionally partially applying any - // arguments. - proxy: function( fn, context ) { - var args, proxy, tmp; - - if ( typeof context === "string" ) { - tmp = fn[ context ]; - context = fn; - fn = tmp; - } - - // Quick check to determine if target is callable, in the spec - // this throws a TypeError, but we will just return undefined. - if ( !jQuery.isFunction( fn ) ) { - return undefined; - } - - // Simulated bind - args = slice.call( arguments, 2 ); - proxy = function() { - return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); - }; - - // Set the guid of unique handler to the same of original handler, so it can be removed - proxy.guid = fn.guid = fn.guid || jQuery.guid++; - - return proxy; - }, - - now: function() { - return +( new Date() ); - }, - - // jQuery.support is not used in Core but other projects attach their - // properties to it so it needs to exist. - support: support -}); - -// Populate the class2type map -jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -}); - -function isArraylike( obj ) { - var length = obj.length, - type = jQuery.type( obj ); - - if ( type === "function" || jQuery.isWindow( obj ) ) { - return false; - } - - if ( obj.nodeType === 1 && length ) { - return true; - } - - return type === "array" || length === 0 || - typeof length === "number" && length > 0 && ( length - 1 ) in obj; -} -var Sizzle = -/*! - * Sizzle CSS Selector Engine v2.2.0-pre - * http://sizzlejs.com/ - * - * Copyright 2008, 2014 jQuery Foundation, Inc. and other contributors - * Released under the MIT license - * http://jquery.org/license - * - * Date: 2014-12-16 - */ -(function( window ) { - -var i, - support, - Expr, - getText, - isXML, - tokenize, - compile, - select, - outermostContext, - sortInput, - hasDuplicate, - - // Local document vars - setDocument, - document, - docElem, - documentIsHTML, - rbuggyQSA, - rbuggyMatches, - matches, - contains, - - // Instance-specific data - expando = "sizzle" + 1 * new Date(), - preferredDoc = window.document, - dirruns = 0, - done = 0, - classCache = createCache(), - tokenCache = createCache(), - compilerCache = createCache(), - sortOrder = function( a, b ) { - if ( a === b ) { - hasDuplicate = true; - } - return 0; - }, - - // General-purpose constants - MAX_NEGATIVE = 1 << 31, - - // Instance methods - hasOwn = ({}).hasOwnProperty, - arr = [], - pop = arr.pop, - push_native = arr.push, - push = arr.push, - slice = arr.slice, - // Use a stripped-down indexOf as it's faster than native - // http://jsperf.com/thor-indexof-vs-for/5 - indexOf = function( list, elem ) { - var i = 0, - len = list.length; - for ( ; i < len; i++ ) { - if ( list[i] === elem ) { - return i; - } - } - return -1; - }, - - booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", - - // Regular expressions - - // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace - whitespace = "[\\x20\\t\\r\\n\\f]", - // http://www.w3.org/TR/css3-syntax/#characters - characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", - - // Loosely modeled on CSS identifier characters - // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors - // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier - identifier = characterEncoding.replace( "w", "w#" ), - - // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors - attributes = "\\[" + whitespace + "*(" + characterEncoding + ")(?:" + whitespace + - // Operator (capture 2) - "*([*^$|!~]?=)" + whitespace + - // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" - "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + - "*\\]", - - pseudos = ":(" + characterEncoding + ")(?:\\((" + - // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: - // 1. quoted (capture 3; capture 4 or capture 5) - "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + - // 2. simple (capture 6) - "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + - // 3. anything else (capture 2) - ".*" + - ")\\)|)", - - // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter - rwhitespace = new RegExp( whitespace + "+", "g" ), - rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), - - rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), - rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), - - rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), - - rpseudo = new RegExp( pseudos ), - ridentifier = new RegExp( "^" + identifier + "$" ), - - matchExpr = { - "ID": new RegExp( "^#(" + characterEncoding + ")" ), - "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), - "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ), - "ATTR": new RegExp( "^" + attributes ), - "PSEUDO": new RegExp( "^" + pseudos ), - "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + - "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + - "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), - "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), - // For use in libraries implementing .is() - // We use this for POS matching in `select` - "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + - whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) - }, - - rinputs = /^(?:input|select|textarea|button)$/i, - rheader = /^h\d$/i, - - rnative = /^[^{]+\{\s*\[native \w/, - - // Easily-parseable/retrievable ID or TAG or CLASS selectors - rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, - - rsibling = /[+~]/, - rescape = /'|\\/g, - - // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters - runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), - funescape = function( _, escaped, escapedWhitespace ) { - var high = "0x" + escaped - 0x10000; - // NaN means non-codepoint - // Support: Firefox<24 - // Workaround erroneous numeric interpretation of +"0x" - return high !== high || escapedWhitespace ? - escaped : - high < 0 ? - // BMP codepoint - String.fromCharCode( high + 0x10000 ) : - // Supplemental Plane codepoint (surrogate pair) - String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); - }, - - // Used for iframes - // See setDocument() - // Removing the function wrapper causes a "Permission Denied" - // error in IE - unloadHandler = function() { - setDocument(); - }; - -// Optimize for push.apply( _, NodeList ) -try { - push.apply( - (arr = slice.call( preferredDoc.childNodes )), - preferredDoc.childNodes - ); - // Support: Android<4.0 - // Detect silently failing push.apply - arr[ preferredDoc.childNodes.length ].nodeType; -} catch ( e ) { - push = { apply: arr.length ? - - // Leverage slice if possible - function( target, els ) { - push_native.apply( target, slice.call(els) ); - } : - - // Support: IE<9 - // Otherwise append directly - function( target, els ) { - var j = target.length, - i = 0; - // Can't trust NodeList.length - while ( (target[j++] = els[i++]) ) {} - target.length = j - 1; - } - }; -} - -function Sizzle( selector, context, results, seed ) { - var match, elem, m, nodeType, - // QSA vars - i, groups, old, nid, newContext, newSelector; - - if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { - setDocument( context ); - } - - context = context || document; - results = results || []; - nodeType = context.nodeType; - - if ( typeof selector !== "string" || !selector || - nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { - - return results; - } - - if ( !seed && documentIsHTML ) { - - // Try to shortcut find operations when possible (e.g., not under DocumentFragment) - if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { - // Speed-up: Sizzle("#ID") - if ( (m = match[1]) ) { - if ( nodeType === 9 ) { - elem = context.getElementById( m ); - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document (jQuery #6963) - if ( elem && elem.parentNode ) { - // Handle the case where IE, Opera, and Webkit return items - // by name instead of ID - if ( elem.id === m ) { - results.push( elem ); - return results; - } - } else { - return results; - } - } else { - // Context is not a document - if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && - contains( context, elem ) && elem.id === m ) { - results.push( elem ); - return results; - } - } - - // Speed-up: Sizzle("TAG") - } else if ( match[2] ) { - push.apply( results, context.getElementsByTagName( selector ) ); - return results; - - // Speed-up: Sizzle(".CLASS") - } else if ( (m = match[3]) && support.getElementsByClassName ) { - push.apply( results, context.getElementsByClassName( m ) ); - return results; - } - } - - // QSA path - if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { - nid = old = expando; - newContext = context; - newSelector = nodeType !== 1 && selector; - - // qSA works strangely on Element-rooted queries - // We can work around this by specifying an extra ID on the root - // and working up from there (Thanks to Andrew Dupont for the technique) - // IE 8 doesn't work on object elements - if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { - groups = tokenize( selector ); - - if ( (old = context.getAttribute("id")) ) { - nid = old.replace( rescape, "\\$&" ); - } else { - context.setAttribute( "id", nid ); - } - nid = "[id='" + nid + "'] "; - - i = groups.length; - while ( i-- ) { - groups[i] = nid + toSelector( groups[i] ); - } - newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context; - newSelector = groups.join(","); - } - - if ( newSelector ) { - try { - push.apply( results, - newContext.querySelectorAll( newSelector ) - ); - return results; - } catch(qsaError) { - } finally { - if ( !old ) { - context.removeAttribute("id"); - } - } - } - } - } - - // All others - return select( selector.replace( rtrim, "$1" ), context, results, seed ); -} - -/** - * Create key-value caches of limited size - * @returns {Function(string, Object)} Returns the Object data after storing it on itself with - * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) - * deleting the oldest entry - */ -function createCache() { - var keys = []; - - function cache( key, value ) { - // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) - if ( keys.push( key + " " ) > Expr.cacheLength ) { - // Only keep the most recent entries - delete cache[ keys.shift() ]; - } - return (cache[ key + " " ] = value); - } - return cache; -} - -/** - * Mark a function for special use by Sizzle - * @param {Function} fn The function to mark - */ -function markFunction( fn ) { - fn[ expando ] = true; - return fn; -} - -/** - * Support testing using an element - * @param {Function} fn Passed the created div and expects a boolean result - */ -function assert( fn ) { - var div = document.createElement("div"); - - try { - return !!fn( div ); - } catch (e) { - return false; - } finally { - // Remove from its parent by default - if ( div.parentNode ) { - div.parentNode.removeChild( div ); - } - // release memory in IE - div = null; - } -} - -/** - * Adds the same handler for all of the specified attrs - * @param {String} attrs Pipe-separated list of attributes - * @param {Function} handler The method that will be applied - */ -function addHandle( attrs, handler ) { - var arr = attrs.split("|"), - i = attrs.length; - - while ( i-- ) { - Expr.attrHandle[ arr[i] ] = handler; - } -} - -/** - * Checks document order of two siblings - * @param {Element} a - * @param {Element} b - * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b - */ -function siblingCheck( a, b ) { - var cur = b && a, - diff = cur && a.nodeType === 1 && b.nodeType === 1 && - ( ~b.sourceIndex || MAX_NEGATIVE ) - - ( ~a.sourceIndex || MAX_NEGATIVE ); - - // Use IE sourceIndex if available on both nodes - if ( diff ) { - return diff; - } - - // Check if b follows a - if ( cur ) { - while ( (cur = cur.nextSibling) ) { - if ( cur === b ) { - return -1; - } - } - } - - return a ? 1 : -1; -} - -/** - * Returns a function to use in pseudos for input types - * @param {String} type - */ -function createInputPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for buttons - * @param {String} type - */ -function createButtonPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for positionals - * @param {Function} fn - */ -function createPositionalPseudo( fn ) { - return markFunction(function( argument ) { - argument = +argument; - return markFunction(function( seed, matches ) { - var j, - matchIndexes = fn( [], seed.length, argument ), - i = matchIndexes.length; - - // Match elements found at the specified indexes - while ( i-- ) { - if ( seed[ (j = matchIndexes[i]) ] ) { - seed[j] = !(matches[j] = seed[j]); - } - } - }); - }); -} - -/** - * Checks a node for validity as a Sizzle context - * @param {Element|Object=} context - * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value - */ -function testContext( context ) { - return context && typeof context.getElementsByTagName !== "undefined" && context; -} - -// Expose support vars for convenience -support = Sizzle.support = {}; - -/** - * Detects XML nodes - * @param {Element|Object} elem An element or a document - * @returns {Boolean} True iff elem is a non-HTML XML node - */ -isXML = Sizzle.isXML = function( elem ) { - // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) - var documentElement = elem && (elem.ownerDocument || elem).documentElement; - return documentElement ? documentElement.nodeName !== "HTML" : false; -}; - -/** - * Sets document-related variables once based on the current document - * @param {Element|Object} [doc] An element or document object to use to set the document - * @returns {Object} Returns the current document - */ -setDocument = Sizzle.setDocument = function( node ) { - var hasCompare, parent, - doc = node ? node.ownerDocument || node : preferredDoc; - - // If no document and documentElement is available, return - if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { - return document; - } - - // Set our document - document = doc; - docElem = doc.documentElement; - parent = doc.defaultView; - - // Support: IE>8 - // If iframe document is assigned to "document" variable and if iframe has been reloaded, - // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936 - // IE6-8 do not support the defaultView property so parent will be undefined - if ( parent && parent !== parent.top ) { - // IE11 does not have attachEvent, so all must suffer - if ( parent.addEventListener ) { - parent.addEventListener( "unload", unloadHandler, false ); - } else if ( parent.attachEvent ) { - parent.attachEvent( "onunload", unloadHandler ); - } - } - - /* Support tests - ---------------------------------------------------------------------- */ - documentIsHTML = !isXML( doc ); - - /* Attributes - ---------------------------------------------------------------------- */ - - // Support: IE<8 - // Verify that getAttribute really returns attributes and not properties - // (excepting IE8 booleans) - support.attributes = assert(function( div ) { - div.className = "i"; - return !div.getAttribute("className"); - }); - - /* getElement(s)By* - ---------------------------------------------------------------------- */ - - // Check if getElementsByTagName("*") returns only elements - support.getElementsByTagName = assert(function( div ) { - div.appendChild( doc.createComment("") ); - return !div.getElementsByTagName("*").length; - }); - - // Support: IE<9 - support.getElementsByClassName = rnative.test( doc.getElementsByClassName ); - - // Support: IE<10 - // Check if getElementById returns elements by name - // The broken getElementById methods don't pick up programatically-set names, - // so use a roundabout getElementsByName test - support.getById = assert(function( div ) { - docElem.appendChild( div ).id = expando; - return !doc.getElementsByName || !doc.getElementsByName( expando ).length; - }); - - // ID find and filter - if ( support.getById ) { - Expr.find["ID"] = function( id, context ) { - if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { - var m = context.getElementById( id ); - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - return m && m.parentNode ? [ m ] : []; - } - }; - Expr.filter["ID"] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - return elem.getAttribute("id") === attrId; - }; - }; - } else { - // Support: IE6/7 - // getElementById is not reliable as a find shortcut - delete Expr.find["ID"]; - - Expr.filter["ID"] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); - return node && node.value === attrId; - }; - }; - } - - // Tag - Expr.find["TAG"] = support.getElementsByTagName ? - function( tag, context ) { - if ( typeof context.getElementsByTagName !== "undefined" ) { - return context.getElementsByTagName( tag ); - - // DocumentFragment nodes don't have gEBTN - } else if ( support.qsa ) { - return context.querySelectorAll( tag ); - } - } : - - function( tag, context ) { - var elem, - tmp = [], - i = 0, - // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too - results = context.getElementsByTagName( tag ); - - // Filter out possible comments - if ( tag === "*" ) { - while ( (elem = results[i++]) ) { - if ( elem.nodeType === 1 ) { - tmp.push( elem ); - } - } - - return tmp; - } - return results; - }; - - // Class - Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { - if ( documentIsHTML ) { - return context.getElementsByClassName( className ); - } - }; - - /* QSA/matchesSelector - ---------------------------------------------------------------------- */ - - // QSA and matchesSelector support - - // matchesSelector(:active) reports false when true (IE9/Opera 11.5) - rbuggyMatches = []; - - // qSa(:focus) reports false when true (Chrome 21) - // We allow this because of a bug in IE8/9 that throws an error - // whenever `document.activeElement` is accessed on an iframe - // So, we allow :focus to pass through QSA all the time to avoid the IE error - // See http://bugs.jquery.com/ticket/13378 - rbuggyQSA = []; - - if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) { - // Build QSA regex - // Regex strategy adopted from Diego Perini - assert(function( div ) { - // Select is set to empty string on purpose - // This is to test IE's treatment of not explicitly - // setting a boolean content attribute, - // since its presence should be enough - // http://bugs.jquery.com/ticket/12359 - docElem.appendChild( div ).innerHTML = "" + - ""; - - // Support: IE8, Opera 11-12.16 - // Nothing should be selected when empty strings follow ^= or $= or *= - // The test attribute must be unknown in Opera but "safe" for WinRT - // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section - if ( div.querySelectorAll("[msallowcapture^='']").length ) { - rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); - } - - // Support: IE8 - // Boolean attributes and "value" are not treated correctly - if ( !div.querySelectorAll("[selected]").length ) { - rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); - } - - // Support: Chrome<29, Android<4.2+, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.7+ - if ( !div.querySelectorAll( "[id~=" + expando + "-]" ).length ) { - rbuggyQSA.push("~="); - } - - // Webkit/Opera - :checked should return selected option elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - // IE8 throws error here and will not see later tests - if ( !div.querySelectorAll(":checked").length ) { - rbuggyQSA.push(":checked"); - } - - // Support: Safari 8+, iOS 8+ - // https://bugs.webkit.org/show_bug.cgi?id=136851 - // In-page `selector#id sibing-combinator selector` fails - if ( !div.querySelectorAll( "a#" + expando + "+*" ).length ) { - rbuggyQSA.push(".#.+[+~]"); - } - }); - - assert(function( div ) { - // Support: Windows 8 Native Apps - // The type and name attributes are restricted during .innerHTML assignment - var input = doc.createElement("input"); - input.setAttribute( "type", "hidden" ); - div.appendChild( input ).setAttribute( "name", "D" ); - - // Support: IE8 - // Enforce case-sensitivity of name attribute - if ( div.querySelectorAll("[name=d]").length ) { - rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); - } - - // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) - // IE8 throws error here and will not see later tests - if ( !div.querySelectorAll(":enabled").length ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } - - // Opera 10-11 does not throw on post-comma invalid pseudos - div.querySelectorAll("*,:x"); - rbuggyQSA.push(",.*:"); - }); - } - - if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || - docElem.webkitMatchesSelector || - docElem.mozMatchesSelector || - docElem.oMatchesSelector || - docElem.msMatchesSelector) )) ) { - - assert(function( div ) { - // Check to see if it's possible to do matchesSelector - // on a disconnected node (IE 9) - support.disconnectedMatch = matches.call( div, "div" ); - - // This should fail with an exception - // Gecko does not error, returns false instead - matches.call( div, "[s!='']:x" ); - rbuggyMatches.push( "!=", pseudos ); - }); - } - - rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); - rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); - - /* Contains - ---------------------------------------------------------------------- */ - hasCompare = rnative.test( docElem.compareDocumentPosition ); - - // Element contains another - // Purposefully does not implement inclusive descendent - // As in, an element does not contain itself - contains = hasCompare || rnative.test( docElem.contains ) ? - function( a, b ) { - var adown = a.nodeType === 9 ? a.documentElement : a, - bup = b && b.parentNode; - return a === bup || !!( bup && bup.nodeType === 1 && ( - adown.contains ? - adown.contains( bup ) : - a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 - )); - } : - function( a, b ) { - if ( b ) { - while ( (b = b.parentNode) ) { - if ( b === a ) { - return true; - } - } - } - return false; - }; - - /* Sorting - ---------------------------------------------------------------------- */ - - // Document order sorting - sortOrder = hasCompare ? - function( a, b ) { - - // Flag for duplicate removal - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - // Sort on method existence if only one input has compareDocumentPosition - var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; - if ( compare ) { - return compare; - } - - // Calculate position if both inputs belong to the same document - compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? - a.compareDocumentPosition( b ) : - - // Otherwise we know they are disconnected - 1; - - // Disconnected nodes - if ( compare & 1 || - (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { - - // Choose the first element that is related to our preferred document - if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { - return -1; - } - if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { - return 1; - } - - // Maintain original order - return sortInput ? - ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : - 0; - } - - return compare & 4 ? -1 : 1; - } : - function( a, b ) { - // Exit early if the nodes are identical - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - var cur, - i = 0, - aup = a.parentNode, - bup = b.parentNode, - ap = [ a ], - bp = [ b ]; - - // Parentless nodes are either documents or disconnected - if ( !aup || !bup ) { - return a === doc ? -1 : - b === doc ? 1 : - aup ? -1 : - bup ? 1 : - sortInput ? - ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : - 0; - - // If the nodes are siblings, we can do a quick check - } else if ( aup === bup ) { - return siblingCheck( a, b ); - } - - // Otherwise we need full lists of their ancestors for comparison - cur = a; - while ( (cur = cur.parentNode) ) { - ap.unshift( cur ); - } - cur = b; - while ( (cur = cur.parentNode) ) { - bp.unshift( cur ); - } - - // Walk down the tree looking for a discrepancy - while ( ap[i] === bp[i] ) { - i++; - } - - return i ? - // Do a sibling check if the nodes have a common ancestor - siblingCheck( ap[i], bp[i] ) : - - // Otherwise nodes in our document sort first - ap[i] === preferredDoc ? -1 : - bp[i] === preferredDoc ? 1 : - 0; - }; - - return doc; -}; - -Sizzle.matches = function( expr, elements ) { - return Sizzle( expr, null, null, elements ); -}; - -Sizzle.matchesSelector = function( elem, expr ) { - // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { - setDocument( elem ); - } - - // Make sure that attribute selectors are quoted - expr = expr.replace( rattributeQuotes, "='$1']" ); - - if ( support.matchesSelector && documentIsHTML && - ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && - ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { - - try { - var ret = matches.call( elem, expr ); - - // IE 9's matchesSelector returns false on disconnected nodes - if ( ret || support.disconnectedMatch || - // As well, disconnected nodes are said to be in a document - // fragment in IE 9 - elem.document && elem.document.nodeType !== 11 ) { - return ret; - } - } catch (e) {} - } - - return Sizzle( expr, document, null, [ elem ] ).length > 0; -}; - -Sizzle.contains = function( context, elem ) { - // Set document vars if needed - if ( ( context.ownerDocument || context ) !== document ) { - setDocument( context ); - } - return contains( context, elem ); -}; - -Sizzle.attr = function( elem, name ) { - // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { - setDocument( elem ); - } - - var fn = Expr.attrHandle[ name.toLowerCase() ], - // Don't get fooled by Object.prototype properties (jQuery #13807) - val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? - fn( elem, name, !documentIsHTML ) : - undefined; - - return val !== undefined ? - val : - support.attributes || !documentIsHTML ? - elem.getAttribute( name ) : - (val = elem.getAttributeNode(name)) && val.specified ? - val.value : - null; -}; - -Sizzle.error = function( msg ) { - throw new Error( "Syntax error, unrecognized expression: " + msg ); -}; - -/** - * Document sorting and removing duplicates - * @param {ArrayLike} results - */ -Sizzle.uniqueSort = function( results ) { - var elem, - duplicates = [], - j = 0, - i = 0; - - // Unless we *know* we can detect duplicates, assume their presence - hasDuplicate = !support.detectDuplicates; - sortInput = !support.sortStable && results.slice( 0 ); - results.sort( sortOrder ); - - if ( hasDuplicate ) { - while ( (elem = results[i++]) ) { - if ( elem === results[ i ] ) { - j = duplicates.push( i ); - } - } - while ( j-- ) { - results.splice( duplicates[ j ], 1 ); - } - } - - // Clear input after sorting to release objects - // See https://github.com/jquery/sizzle/pull/225 - sortInput = null; - - return results; -}; - -/** - * Utility function for retrieving the text value of an array of DOM nodes - * @param {Array|Element} elem - */ -getText = Sizzle.getText = function( elem ) { - var node, - ret = "", - i = 0, - nodeType = elem.nodeType; - - if ( !nodeType ) { - // If no nodeType, this is expected to be an array - while ( (node = elem[i++]) ) { - // Do not traverse comment nodes - ret += getText( node ); - } - } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { - // Use textContent for elements - // innerText usage removed for consistency of new lines (jQuery #11153) - if ( typeof elem.textContent === "string" ) { - return elem.textContent; - } else { - // Traverse its children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - ret += getText( elem ); - } - } - } else if ( nodeType === 3 || nodeType === 4 ) { - return elem.nodeValue; - } - // Do not include comment or processing instruction nodes - - return ret; -}; - -Expr = Sizzle.selectors = { - - // Can be adjusted by the user - cacheLength: 50, - - createPseudo: markFunction, - - match: matchExpr, - - attrHandle: {}, - - find: {}, - - relative: { - ">": { dir: "parentNode", first: true }, - " ": { dir: "parentNode" }, - "+": { dir: "previousSibling", first: true }, - "~": { dir: "previousSibling" } - }, - - preFilter: { - "ATTR": function( match ) { - match[1] = match[1].replace( runescape, funescape ); - - // Move the given value to match[3] whether quoted or unquoted - match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); - - if ( match[2] === "~=" ) { - match[3] = " " + match[3] + " "; - } - - return match.slice( 0, 4 ); - }, - - "CHILD": function( match ) { - /* matches from matchExpr["CHILD"] - 1 type (only|nth|...) - 2 what (child|of-type) - 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) - 4 xn-component of xn+y argument ([+-]?\d*n|) - 5 sign of xn-component - 6 x of xn-component - 7 sign of y-component - 8 y of y-component - */ - match[1] = match[1].toLowerCase(); - - if ( match[1].slice( 0, 3 ) === "nth" ) { - // nth-* requires argument - if ( !match[3] ) { - Sizzle.error( match[0] ); - } - - // numeric x and y parameters for Expr.filter.CHILD - // remember that false/true cast respectively to 0/1 - match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); - match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); - - // other types prohibit arguments - } else if ( match[3] ) { - Sizzle.error( match[0] ); - } - - return match; - }, - - "PSEUDO": function( match ) { - var excess, - unquoted = !match[6] && match[2]; - - if ( matchExpr["CHILD"].test( match[0] ) ) { - return null; - } - - // Accept quoted arguments as-is - if ( match[3] ) { - match[2] = match[4] || match[5] || ""; - - // Strip excess characters from unquoted arguments - } else if ( unquoted && rpseudo.test( unquoted ) && - // Get excess from tokenize (recursively) - (excess = tokenize( unquoted, true )) && - // advance to the next closing parenthesis - (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { - - // excess is a negative index - match[0] = match[0].slice( 0, excess ); - match[2] = unquoted.slice( 0, excess ); - } - - // Return only captures needed by the pseudo filter method (type and argument) - return match.slice( 0, 3 ); - } - }, - - filter: { - - "TAG": function( nodeNameSelector ) { - var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); - return nodeNameSelector === "*" ? - function() { return true; } : - function( elem ) { - return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; - }; - }, - - "CLASS": function( className ) { - var pattern = classCache[ className + " " ]; - - return pattern || - (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && - classCache( className, function( elem ) { - return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); - }); - }, - - "ATTR": function( name, operator, check ) { - return function( elem ) { - var result = Sizzle.attr( elem, name ); - - if ( result == null ) { - return operator === "!="; - } - if ( !operator ) { - return true; - } - - result += ""; - - return operator === "=" ? result === check : - operator === "!=" ? result !== check : - operator === "^=" ? check && result.indexOf( check ) === 0 : - operator === "*=" ? check && result.indexOf( check ) > -1 : - operator === "$=" ? check && result.slice( -check.length ) === check : - operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : - operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : - false; - }; - }, - - "CHILD": function( type, what, argument, first, last ) { - var simple = type.slice( 0, 3 ) !== "nth", - forward = type.slice( -4 ) !== "last", - ofType = what === "of-type"; - - return first === 1 && last === 0 ? - - // Shortcut for :nth-*(n) - function( elem ) { - return !!elem.parentNode; - } : - - function( elem, context, xml ) { - var cache, outerCache, node, diff, nodeIndex, start, - dir = simple !== forward ? "nextSibling" : "previousSibling", - parent = elem.parentNode, - name = ofType && elem.nodeName.toLowerCase(), - useCache = !xml && !ofType; - - if ( parent ) { - - // :(first|last|only)-(child|of-type) - if ( simple ) { - while ( dir ) { - node = elem; - while ( (node = node[ dir ]) ) { - if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) { - return false; - } - } - // Reverse direction for :only-* (if we haven't yet done so) - start = dir = type === "only" && !start && "nextSibling"; - } - return true; - } - - start = [ forward ? parent.firstChild : parent.lastChild ]; - - // non-xml :nth-child(...) stores cache data on `parent` - if ( forward && useCache ) { - // Seek `elem` from a previously-cached index - outerCache = parent[ expando ] || (parent[ expando ] = {}); - cache = outerCache[ type ] || []; - nodeIndex = cache[0] === dirruns && cache[1]; - diff = cache[0] === dirruns && cache[2]; - node = nodeIndex && parent.childNodes[ nodeIndex ]; - - while ( (node = ++nodeIndex && node && node[ dir ] || - - // Fallback to seeking `elem` from the start - (diff = nodeIndex = 0) || start.pop()) ) { - - // When found, cache indexes on `parent` and break - if ( node.nodeType === 1 && ++diff && node === elem ) { - outerCache[ type ] = [ dirruns, nodeIndex, diff ]; - break; - } - } - - // Use previously-cached element index if available - } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) { - diff = cache[1]; - - // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...) - } else { - // Use the same loop as above to seek `elem` from the start - while ( (node = ++nodeIndex && node && node[ dir ] || - (diff = nodeIndex = 0) || start.pop()) ) { - - if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) { - // Cache the index of each encountered element - if ( useCache ) { - (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ]; - } - - if ( node === elem ) { - break; - } - } - } - } - - // Incorporate the offset, then check against cycle size - diff -= last; - return diff === first || ( diff % first === 0 && diff / first >= 0 ); - } - }; - }, - - "PSEUDO": function( pseudo, argument ) { - // pseudo-class names are case-insensitive - // http://www.w3.org/TR/selectors/#pseudo-classes - // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters - // Remember that setFilters inherits from pseudos - var args, - fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || - Sizzle.error( "unsupported pseudo: " + pseudo ); - - // The user may use createPseudo to indicate that - // arguments are needed to create the filter function - // just as Sizzle does - if ( fn[ expando ] ) { - return fn( argument ); - } - - // But maintain support for old signatures - if ( fn.length > 1 ) { - args = [ pseudo, pseudo, "", argument ]; - return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? - markFunction(function( seed, matches ) { - var idx, - matched = fn( seed, argument ), - i = matched.length; - while ( i-- ) { - idx = indexOf( seed, matched[i] ); - seed[ idx ] = !( matches[ idx ] = matched[i] ); - } - }) : - function( elem ) { - return fn( elem, 0, args ); - }; - } - - return fn; - } - }, - - pseudos: { - // Potentially complex pseudos - "not": markFunction(function( selector ) { - // Trim the selector passed to compile - // to avoid treating leading and trailing - // spaces as combinators - var input = [], - results = [], - matcher = compile( selector.replace( rtrim, "$1" ) ); - - return matcher[ expando ] ? - markFunction(function( seed, matches, context, xml ) { - var elem, - unmatched = matcher( seed, null, xml, [] ), - i = seed.length; - - // Match elements unmatched by `matcher` - while ( i-- ) { - if ( (elem = unmatched[i]) ) { - seed[i] = !(matches[i] = elem); - } - } - }) : - function( elem, context, xml ) { - input[0] = elem; - matcher( input, null, xml, results ); - // Don't keep the element (issue #299) - input[0] = null; - return !results.pop(); - }; - }), - - "has": markFunction(function( selector ) { - return function( elem ) { - return Sizzle( selector, elem ).length > 0; - }; - }), - - "contains": markFunction(function( text ) { - text = text.replace( runescape, funescape ); - return function( elem ) { - return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; - }; - }), - - // "Whether an element is represented by a :lang() selector - // is based solely on the element's language value - // being equal to the identifier C, - // or beginning with the identifier C immediately followed by "-". - // The matching of C against the element's language value is performed case-insensitively. - // The identifier C does not have to be a valid language name." - // http://www.w3.org/TR/selectors/#lang-pseudo - "lang": markFunction( function( lang ) { - // lang value must be a valid identifier - if ( !ridentifier.test(lang || "") ) { - Sizzle.error( "unsupported lang: " + lang ); - } - lang = lang.replace( runescape, funescape ).toLowerCase(); - return function( elem ) { - var elemLang; - do { - if ( (elemLang = documentIsHTML ? - elem.lang : - elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { - - elemLang = elemLang.toLowerCase(); - return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; - } - } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); - return false; - }; - }), - - // Miscellaneous - "target": function( elem ) { - var hash = window.location && window.location.hash; - return hash && hash.slice( 1 ) === elem.id; - }, - - "root": function( elem ) { - return elem === docElem; - }, - - "focus": function( elem ) { - return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); - }, - - // Boolean properties - "enabled": function( elem ) { - return elem.disabled === false; - }, - - "disabled": function( elem ) { - return elem.disabled === true; - }, - - "checked": function( elem ) { - // In CSS3, :checked should return both checked and selected elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - var nodeName = elem.nodeName.toLowerCase(); - return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); - }, - - "selected": function( elem ) { - // Accessing this property makes selected-by-default - // options in Safari work properly - if ( elem.parentNode ) { - elem.parentNode.selectedIndex; - } - - return elem.selected === true; - }, - - // Contents - "empty": function( elem ) { - // http://www.w3.org/TR/selectors/#empty-pseudo - // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), - // but not by others (comment: 8; processing instruction: 7; etc.) - // nodeType < 6 works because attributes (2) do not appear as children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - if ( elem.nodeType < 6 ) { - return false; - } - } - return true; - }, - - "parent": function( elem ) { - return !Expr.pseudos["empty"]( elem ); - }, - - // Element/input types - "header": function( elem ) { - return rheader.test( elem.nodeName ); - }, - - "input": function( elem ) { - return rinputs.test( elem.nodeName ); - }, - - "button": function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === "button" || name === "button"; - }, - - "text": function( elem ) { - var attr; - return elem.nodeName.toLowerCase() === "input" && - elem.type === "text" && - - // Support: IE<8 - // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" - ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); - }, - - // Position-in-collection - "first": createPositionalPseudo(function() { - return [ 0 ]; - }), - - "last": createPositionalPseudo(function( matchIndexes, length ) { - return [ length - 1 ]; - }), - - "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { - return [ argument < 0 ? argument + length : argument ]; - }), - - "even": createPositionalPseudo(function( matchIndexes, length ) { - var i = 0; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "odd": createPositionalPseudo(function( matchIndexes, length ) { - var i = 1; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; - for ( ; --i >= 0; ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; - for ( ; ++i < length; ) { - matchIndexes.push( i ); - } - return matchIndexes; - }) - } -}; - -Expr.pseudos["nth"] = Expr.pseudos["eq"]; - -// Add button/input type pseudos -for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { - Expr.pseudos[ i ] = createInputPseudo( i ); -} -for ( i in { submit: true, reset: true } ) { - Expr.pseudos[ i ] = createButtonPseudo( i ); -} - -// Easy API for creating new setFilters -function setFilters() {} -setFilters.prototype = Expr.filters = Expr.pseudos; -Expr.setFilters = new setFilters(); - -tokenize = Sizzle.tokenize = function( selector, parseOnly ) { - var matched, match, tokens, type, - soFar, groups, preFilters, - cached = tokenCache[ selector + " " ]; - - if ( cached ) { - return parseOnly ? 0 : cached.slice( 0 ); - } - - soFar = selector; - groups = []; - preFilters = Expr.preFilter; - - while ( soFar ) { - - // Comma and first run - if ( !matched || (match = rcomma.exec( soFar )) ) { - if ( match ) { - // Don't consume trailing commas as valid - soFar = soFar.slice( match[0].length ) || soFar; - } - groups.push( (tokens = []) ); - } - - matched = false; - - // Combinators - if ( (match = rcombinators.exec( soFar )) ) { - matched = match.shift(); - tokens.push({ - value: matched, - // Cast descendant combinators to space - type: match[0].replace( rtrim, " " ) - }); - soFar = soFar.slice( matched.length ); - } - - // Filters - for ( type in Expr.filter ) { - if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || - (match = preFilters[ type ]( match ))) ) { - matched = match.shift(); - tokens.push({ - value: matched, - type: type, - matches: match - }); - soFar = soFar.slice( matched.length ); - } - } - - if ( !matched ) { - break; - } - } - - // Return the length of the invalid excess - // if we're just parsing - // Otherwise, throw an error or return tokens - return parseOnly ? - soFar.length : - soFar ? - Sizzle.error( selector ) : - // Cache the tokens - tokenCache( selector, groups ).slice( 0 ); -}; - -function toSelector( tokens ) { - var i = 0, - len = tokens.length, - selector = ""; - for ( ; i < len; i++ ) { - selector += tokens[i].value; - } - return selector; -} - -function addCombinator( matcher, combinator, base ) { - var dir = combinator.dir, - checkNonElements = base && dir === "parentNode", - doneName = done++; - - return combinator.first ? - // Check against closest ancestor/preceding element - function( elem, context, xml ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - return matcher( elem, context, xml ); - } - } - } : - - // Check against all ancestor/preceding elements - function( elem, context, xml ) { - var oldCache, outerCache, - newCache = [ dirruns, doneName ]; - - // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching - if ( xml ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - if ( matcher( elem, context, xml ) ) { - return true; - } - } - } - } else { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - outerCache = elem[ expando ] || (elem[ expando ] = {}); - if ( (oldCache = outerCache[ dir ]) && - oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { - - // Assign to newCache so results back-propagate to previous elements - return (newCache[ 2 ] = oldCache[ 2 ]); - } else { - // Reuse newcache so results back-propagate to previous elements - outerCache[ dir ] = newCache; - - // A match means we're done; a fail means we have to keep checking - if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { - return true; - } - } - } - } - } - }; -} - -function elementMatcher( matchers ) { - return matchers.length > 1 ? - function( elem, context, xml ) { - var i = matchers.length; - while ( i-- ) { - if ( !matchers[i]( elem, context, xml ) ) { - return false; - } - } - return true; - } : - matchers[0]; -} - -function multipleContexts( selector, contexts, results ) { - var i = 0, - len = contexts.length; - for ( ; i < len; i++ ) { - Sizzle( selector, contexts[i], results ); - } - return results; -} - -function condense( unmatched, map, filter, context, xml ) { - var elem, - newUnmatched = [], - i = 0, - len = unmatched.length, - mapped = map != null; - - for ( ; i < len; i++ ) { - if ( (elem = unmatched[i]) ) { - if ( !filter || filter( elem, context, xml ) ) { - newUnmatched.push( elem ); - if ( mapped ) { - map.push( i ); - } - } - } - } - - return newUnmatched; -} - -function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { - if ( postFilter && !postFilter[ expando ] ) { - postFilter = setMatcher( postFilter ); - } - if ( postFinder && !postFinder[ expando ] ) { - postFinder = setMatcher( postFinder, postSelector ); - } - return markFunction(function( seed, results, context, xml ) { - var temp, i, elem, - preMap = [], - postMap = [], - preexisting = results.length, - - // Get initial elements from seed or context - elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), - - // Prefilter to get matcher input, preserving a map for seed-results synchronization - matcherIn = preFilter && ( seed || !selector ) ? - condense( elems, preMap, preFilter, context, xml ) : - elems, - - matcherOut = matcher ? - // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, - postFinder || ( seed ? preFilter : preexisting || postFilter ) ? - - // ...intermediate processing is necessary - [] : - - // ...otherwise use results directly - results : - matcherIn; - - // Find primary matches - if ( matcher ) { - matcher( matcherIn, matcherOut, context, xml ); - } - - // Apply postFilter - if ( postFilter ) { - temp = condense( matcherOut, postMap ); - postFilter( temp, [], context, xml ); - - // Un-match failing elements by moving them back to matcherIn - i = temp.length; - while ( i-- ) { - if ( (elem = temp[i]) ) { - matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); - } - } - } - - if ( seed ) { - if ( postFinder || preFilter ) { - if ( postFinder ) { - // Get the final matcherOut by condensing this intermediate into postFinder contexts - temp = []; - i = matcherOut.length; - while ( i-- ) { - if ( (elem = matcherOut[i]) ) { - // Restore matcherIn since elem is not yet a final match - temp.push( (matcherIn[i] = elem) ); - } - } - postFinder( null, (matcherOut = []), temp, xml ); - } - - // Move matched elements from seed to results to keep them synchronized - i = matcherOut.length; - while ( i-- ) { - if ( (elem = matcherOut[i]) && - (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { - - seed[temp] = !(results[temp] = elem); - } - } - } - - // Add elements to results, through postFinder if defined - } else { - matcherOut = condense( - matcherOut === results ? - matcherOut.splice( preexisting, matcherOut.length ) : - matcherOut - ); - if ( postFinder ) { - postFinder( null, results, matcherOut, xml ); - } else { - push.apply( results, matcherOut ); - } - } - }); -} - -function matcherFromTokens( tokens ) { - var checkContext, matcher, j, - len = tokens.length, - leadingRelative = Expr.relative[ tokens[0].type ], - implicitRelative = leadingRelative || Expr.relative[" "], - i = leadingRelative ? 1 : 0, - - // The foundational matcher ensures that elements are reachable from top-level context(s) - matchContext = addCombinator( function( elem ) { - return elem === checkContext; - }, implicitRelative, true ), - matchAnyContext = addCombinator( function( elem ) { - return indexOf( checkContext, elem ) > -1; - }, implicitRelative, true ), - matchers = [ function( elem, context, xml ) { - var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( - (checkContext = context).nodeType ? - matchContext( elem, context, xml ) : - matchAnyContext( elem, context, xml ) ); - // Avoid hanging onto element (issue #299) - checkContext = null; - return ret; - } ]; - - for ( ; i < len; i++ ) { - if ( (matcher = Expr.relative[ tokens[i].type ]) ) { - matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; - } else { - matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); - - // Return special upon seeing a positional matcher - if ( matcher[ expando ] ) { - // Find the next relative operator (if any) for proper handling - j = ++i; - for ( ; j < len; j++ ) { - if ( Expr.relative[ tokens[j].type ] ) { - break; - } - } - return setMatcher( - i > 1 && elementMatcher( matchers ), - i > 1 && toSelector( - // If the preceding token was a descendant combinator, insert an implicit any-element `*` - tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) - ).replace( rtrim, "$1" ), - matcher, - i < j && matcherFromTokens( tokens.slice( i, j ) ), - j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), - j < len && toSelector( tokens ) - ); - } - matchers.push( matcher ); - } - } - - return elementMatcher( matchers ); -} - -function matcherFromGroupMatchers( elementMatchers, setMatchers ) { - var bySet = setMatchers.length > 0, - byElement = elementMatchers.length > 0, - superMatcher = function( seed, context, xml, results, outermost ) { - var elem, j, matcher, - matchedCount = 0, - i = "0", - unmatched = seed && [], - setMatched = [], - contextBackup = outermostContext, - // We must always have either seed elements or outermost context - elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), - // Use integer dirruns iff this is the outermost matcher - dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), - len = elems.length; - - if ( outermost ) { - outermostContext = context !== document && context; - } - - // Add elements passing elementMatchers directly to results - // Keep `i` a string if there are no elements so `matchedCount` will be "00" below - // Support: IE<9, Safari - // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id - for ( ; i !== len && (elem = elems[i]) != null; i++ ) { - if ( byElement && elem ) { - j = 0; - while ( (matcher = elementMatchers[j++]) ) { - if ( matcher( elem, context, xml ) ) { - results.push( elem ); - break; - } - } - if ( outermost ) { - dirruns = dirrunsUnique; - } - } - - // Track unmatched elements for set filters - if ( bySet ) { - // They will have gone through all possible matchers - if ( (elem = !matcher && elem) ) { - matchedCount--; - } - - // Lengthen the array for every element, matched or not - if ( seed ) { - unmatched.push( elem ); - } - } - } - - // Apply set filters to unmatched elements - matchedCount += i; - if ( bySet && i !== matchedCount ) { - j = 0; - while ( (matcher = setMatchers[j++]) ) { - matcher( unmatched, setMatched, context, xml ); - } - - if ( seed ) { - // Reintegrate element matches to eliminate the need for sorting - if ( matchedCount > 0 ) { - while ( i-- ) { - if ( !(unmatched[i] || setMatched[i]) ) { - setMatched[i] = pop.call( results ); - } - } - } - - // Discard index placeholder values to get only actual matches - setMatched = condense( setMatched ); - } - - // Add matches to results - push.apply( results, setMatched ); - - // Seedless set matches succeeding multiple successful matchers stipulate sorting - if ( outermost && !seed && setMatched.length > 0 && - ( matchedCount + setMatchers.length ) > 1 ) { - - Sizzle.uniqueSort( results ); - } - } - - // Override manipulation of globals by nested matchers - if ( outermost ) { - dirruns = dirrunsUnique; - outermostContext = contextBackup; - } - - return unmatched; - }; - - return bySet ? - markFunction( superMatcher ) : - superMatcher; -} - -compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { - var i, - setMatchers = [], - elementMatchers = [], - cached = compilerCache[ selector + " " ]; - - if ( !cached ) { - // Generate a function of recursive functions that can be used to check each element - if ( !match ) { - match = tokenize( selector ); - } - i = match.length; - while ( i-- ) { - cached = matcherFromTokens( match[i] ); - if ( cached[ expando ] ) { - setMatchers.push( cached ); - } else { - elementMatchers.push( cached ); - } - } - - // Cache the compiled function - cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); - - // Save selector and tokenization - cached.selector = selector; - } - return cached; -}; - -/** - * A low-level selection function that works with Sizzle's compiled - * selector functions - * @param {String|Function} selector A selector or a pre-compiled - * selector function built with Sizzle.compile - * @param {Element} context - * @param {Array} [results] - * @param {Array} [seed] A set of elements to match against - */ -select = Sizzle.select = function( selector, context, results, seed ) { - var i, tokens, token, type, find, - compiled = typeof selector === "function" && selector, - match = !seed && tokenize( (selector = compiled.selector || selector) ); - - results = results || []; - - // Try to minimize operations if there is no seed and only one group - if ( match.length === 1 ) { - - // Take a shortcut and set the context if the root selector is an ID - tokens = match[0] = match[0].slice( 0 ); - if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && - support.getById && context.nodeType === 9 && documentIsHTML && - Expr.relative[ tokens[1].type ] ) { - - context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; - if ( !context ) { - return results; - - // Precompiled matchers will still verify ancestry, so step up a level - } else if ( compiled ) { - context = context.parentNode; - } - - selector = selector.slice( tokens.shift().value.length ); - } - - // Fetch a seed set for right-to-left matching - i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; - while ( i-- ) { - token = tokens[i]; - - // Abort if we hit a combinator - if ( Expr.relative[ (type = token.type) ] ) { - break; - } - if ( (find = Expr.find[ type ]) ) { - // Search, expanding context for leading sibling combinators - if ( (seed = find( - token.matches[0].replace( runescape, funescape ), - rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context - )) ) { - - // If seed is empty or no tokens remain, we can return early - tokens.splice( i, 1 ); - selector = seed.length && toSelector( tokens ); - if ( !selector ) { - push.apply( results, seed ); - return results; - } - - break; - } - } - } - } - - // Compile and execute a filtering function if one is not provided - // Provide `match` to avoid retokenization if we modified the selector above - ( compiled || compile( selector, match ) )( - seed, - context, - !documentIsHTML, - results, - rsibling.test( selector ) && testContext( context.parentNode ) || context - ); - return results; -}; - -// One-time assignments - -// Sort stability -support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; - -// Support: Chrome 14-35+ -// Always assume duplicates if they aren't passed to the comparison function -support.detectDuplicates = !!hasDuplicate; - -// Initialize against the default document -setDocument(); - -// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) -// Detached nodes confoundingly follow *each other* -support.sortDetached = assert(function( div1 ) { - // Should return 1, but returns 4 (following) - return div1.compareDocumentPosition( document.createElement("div") ) & 1; -}); - -// Support: IE<8 -// Prevent attribute/property "interpolation" -// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx -if ( !assert(function( div ) { - div.innerHTML = ""; - return div.firstChild.getAttribute("href") === "#" ; -}) ) { - addHandle( "type|href|height|width", function( elem, name, isXML ) { - if ( !isXML ) { - return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); - } - }); -} - -// Support: IE<9 -// Use defaultValue in place of getAttribute("value") -if ( !support.attributes || !assert(function( div ) { - div.innerHTML = ""; - div.firstChild.setAttribute( "value", "" ); - return div.firstChild.getAttribute( "value" ) === ""; -}) ) { - addHandle( "value", function( elem, name, isXML ) { - if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { - return elem.defaultValue; - } - }); -} - -// Support: IE<9 -// Use getAttributeNode to fetch booleans when getAttribute lies -if ( !assert(function( div ) { - return div.getAttribute("disabled") == null; -}) ) { - addHandle( booleans, function( elem, name, isXML ) { - var val; - if ( !isXML ) { - return elem[ name ] === true ? name.toLowerCase() : - (val = elem.getAttributeNode( name )) && val.specified ? - val.value : - null; - } - }); -} - -return Sizzle; - -})( window ); - - - -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; -jQuery.expr[":"] = jQuery.expr.pseudos; -jQuery.unique = Sizzle.uniqueSort; -jQuery.text = Sizzle.getText; -jQuery.isXMLDoc = Sizzle.isXML; -jQuery.contains = Sizzle.contains; - - - -var rneedsContext = jQuery.expr.match.needsContext; - -var rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/); - - - -var risSimple = /^.[^:#\[\.,]*$/; - -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, not ) { - if ( jQuery.isFunction( qualifier ) ) { - return jQuery.grep( elements, function( elem, i ) { - /* jshint -W018 */ - return !!qualifier.call( elem, i, elem ) !== not; - }); - - } - - if ( qualifier.nodeType ) { - return jQuery.grep( elements, function( elem ) { - return ( elem === qualifier ) !== not; - }); - - } - - if ( typeof qualifier === "string" ) { - if ( risSimple.test( qualifier ) ) { - return jQuery.filter( qualifier, elements, not ); - } - - qualifier = jQuery.filter( qualifier, elements ); - } - - return jQuery.grep( elements, function( elem ) { - return ( jQuery.inArray( elem, qualifier ) >= 0 ) !== not; - }); -} - -jQuery.filter = function( expr, elems, not ) { - var elem = elems[ 0 ]; - - if ( not ) { - expr = ":not(" + expr + ")"; - } - - return elems.length === 1 && elem.nodeType === 1 ? - jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] : - jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { - return elem.nodeType === 1; - })); -}; - -jQuery.fn.extend({ - find: function( selector ) { - var i, - ret = [], - self = this, - len = self.length; - - if ( typeof selector !== "string" ) { - return this.pushStack( jQuery( selector ).filter(function() { - for ( i = 0; i < len; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - }) ); - } - - for ( i = 0; i < len; i++ ) { - jQuery.find( selector, self[ i ], ret ); - } - - // Needed because $( selector, context ) becomes $( context ).find( selector ) - ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret ); - ret.selector = this.selector ? this.selector + " " + selector : selector; - return ret; - }, - filter: function( selector ) { - return this.pushStack( winnow(this, selector || [], false) ); - }, - not: function( selector ) { - return this.pushStack( winnow(this, selector || [], true) ); - }, - is: function( selector ) { - return !!winnow( - this, - - // If this is a positional/relative selector, check membership in the returned set - // so $("p:first").is("p:last") won't return true for a doc with two "p". - typeof selector === "string" && rneedsContext.test( selector ) ? - jQuery( selector ) : - selector || [], - false - ).length; - } -}); - - -// Initialize a jQuery object - - -// A central reference to the root jQuery(document) -var rootjQuery, - - // Use the correct document accordingly with window argument (sandbox) - document = window.document, - - // A simple way to check for HTML strings - // Prioritize #id over to avoid XSS via location.hash (#9521) - // Strict HTML recognition (#11290: must start with <) - rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/, - - init = jQuery.fn.init = function( selector, context ) { - var match, elem; - - // HANDLE: $(""), $(null), $(undefined), $(false) - if ( !selector ) { - return this; - } - - // Handle HTML strings - if ( typeof selector === "string" ) { - if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { - // Assume that strings that start and end with <> are HTML and skip the regex check - match = [ null, selector, null ]; - - } else { - match = rquickExpr.exec( selector ); - } - - // Match html or make sure no context is specified for #id - if ( match && (match[1] || !context) ) { - - // HANDLE: $(html) -> $(array) - if ( match[1] ) { - context = context instanceof jQuery ? context[0] : context; - - // scripts is true for back-compat - // Intentionally let the error be thrown if parseHTML is not present - jQuery.merge( this, jQuery.parseHTML( - match[1], - context && context.nodeType ? context.ownerDocument || context : document, - true - ) ); - - // HANDLE: $(html, props) - if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { - for ( match in context ) { - // Properties of context are called as methods if possible - if ( jQuery.isFunction( this[ match ] ) ) { - this[ match ]( context[ match ] ); - - // ...and otherwise set as attributes - } else { - this.attr( match, context[ match ] ); - } - } - } - - return this; - - // HANDLE: $(#id) - } else { - elem = document.getElementById( match[2] ); - - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - // Handle the case where IE and Opera return items - // by name instead of ID - if ( elem.id !== match[2] ) { - return rootjQuery.find( selector ); - } - - // Otherwise, we inject the element directly into the jQuery object - this.length = 1; - this[0] = elem; - } - - this.context = document; - this.selector = selector; - return this; - } - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return ( context || rootjQuery ).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return this.constructor( context ).find( selector ); - } - - // HANDLE: $(DOMElement) - } else if ( selector.nodeType ) { - this.context = this[0] = selector; - this.length = 1; - return this; - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) { - return typeof rootjQuery.ready !== "undefined" ? - rootjQuery.ready( selector ) : - // Execute immediately if ready is not present - selector( jQuery ); - } - - if ( selector.selector !== undefined ) { - this.selector = selector.selector; - this.context = selector.context; - } - - return jQuery.makeArray( selector, this ); - }; - -// Give the init function the jQuery prototype for later instantiation -init.prototype = jQuery.fn; - -// Initialize central reference -rootjQuery = jQuery( document ); - - -var rparentsprev = /^(?:parents|prev(?:Until|All))/, - // methods guaranteed to produce a unique set when starting from a unique set - guaranteedUnique = { - children: true, - contents: true, - next: true, - prev: true - }; - -jQuery.extend({ - dir: function( elem, dir, until ) { - var matched = [], - cur = elem[ dir ]; - - while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { - if ( cur.nodeType === 1 ) { - matched.push( cur ); - } - cur = cur[dir]; - } - return matched; - }, - - sibling: function( n, elem ) { - var r = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - r.push( n ); - } - } - - return r; - } -}); - -jQuery.fn.extend({ - has: function( target ) { - var i, - targets = jQuery( target, this ), - len = targets.length; - - return this.filter(function() { - for ( i = 0; i < len; i++ ) { - if ( jQuery.contains( this, targets[i] ) ) { - return true; - } - } - }); - }, - - closest: function( selectors, context ) { - var cur, - i = 0, - l = this.length, - matched = [], - pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? - jQuery( selectors, context || this.context ) : - 0; - - for ( ; i < l; i++ ) { - for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) { - // Always skip document fragments - if ( cur.nodeType < 11 && (pos ? - pos.index(cur) > -1 : - - // Don't pass non-elements to Sizzle - cur.nodeType === 1 && - jQuery.find.matchesSelector(cur, selectors)) ) { - - matched.push( cur ); - break; - } - } - } - - return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched ); - }, - - // Determine the position of an element within - // the matched set of elements - index: function( elem ) { - - // No argument, return index in parent - if ( !elem ) { - return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1; - } - - // index in selector - if ( typeof elem === "string" ) { - return jQuery.inArray( this[0], jQuery( elem ) ); - } - - // Locate the position of the desired element - return jQuery.inArray( - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[0] : elem, this ); - }, - - add: function( selector, context ) { - return this.pushStack( - jQuery.unique( - jQuery.merge( this.get(), jQuery( selector, context ) ) - ) - ); - }, - - addBack: function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter(selector) - ); - } -}); - -function sibling( cur, dir ) { - do { - cur = cur[ dir ]; - } while ( cur && cur.nodeType !== 1 ); - - return cur; -} - -jQuery.each({ - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return jQuery.dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, i, until ) { - return jQuery.dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return sibling( elem, "nextSibling" ); - }, - prev: function( elem ) { - return sibling( elem, "previousSibling" ); - }, - nextAll: function( elem ) { - return jQuery.dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return jQuery.dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, i, until ) { - return jQuery.dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, i, until ) { - return jQuery.dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); - }, - children: function( elem ) { - return jQuery.sibling( elem.firstChild ); - }, - contents: function( elem ) { - return jQuery.nodeName( elem, "iframe" ) ? - elem.contentDocument || elem.contentWindow.document : - jQuery.merge( [], elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var ret = jQuery.map( this, fn, until ); - - if ( name.slice( -5 ) !== "Until" ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - ret = jQuery.filter( selector, ret ); - } - - if ( this.length > 1 ) { - // Remove duplicates - if ( !guaranteedUnique[ name ] ) { - ret = jQuery.unique( ret ); - } - - // Reverse order for parents* and prev-derivatives - if ( rparentsprev.test( name ) ) { - ret = ret.reverse(); - } - } - - return this.pushStack( ret ); - }; -}); -var rnotwhite = (/\S+/g); - - - -// String to Object options format cache -var optionsCache = {}; - -// Convert String-formatted options into Object-formatted ones and store in cache -function createOptions( options ) { - var object = optionsCache[ options ] = {}; - jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) { - object[ flag ] = true; - }); - return object; -} - -/* - * Create a callback list using the following parameters: - * - * options: an optional list of space-separated options that will change how - * the callback list behaves or a more traditional option object - * - * By default a callback list will act like an event callback list and can be - * "fired" multiple times. - * - * Possible options: - * - * once: will ensure the callback list can only be fired once (like a Deferred) - * - * memory: will keep track of previous values and will call any callback added - * after the list has been fired right away with the latest "memorized" - * values (like a Deferred) - * - * unique: will ensure a callback can only be added once (no duplicate in the list) - * - * stopOnFalse: interrupt callings when a callback returns false - * - */ -jQuery.Callbacks = function( options ) { - - // Convert options from String-formatted to Object-formatted if needed - // (we check in cache first) - options = typeof options === "string" ? - ( optionsCache[ options ] || createOptions( options ) ) : - jQuery.extend( {}, options ); - - var // Flag to know if list is currently firing - firing, - // Last fire value (for non-forgettable lists) - memory, - // Flag to know if list was already fired - fired, - // End of the loop when firing - firingLength, - // Index of currently firing callback (modified by remove if needed) - firingIndex, - // First callback to fire (used internally by add and fireWith) - firingStart, - // Actual callback list - list = [], - // Stack of fire calls for repeatable lists - stack = !options.once && [], - // Fire callbacks - fire = function( data ) { - memory = options.memory && data; - fired = true; - firingIndex = firingStart || 0; - firingStart = 0; - firingLength = list.length; - firing = true; - for ( ; list && firingIndex < firingLength; firingIndex++ ) { - if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { - memory = false; // To prevent further calls using add - break; - } - } - firing = false; - if ( list ) { - if ( stack ) { - if ( stack.length ) { - fire( stack.shift() ); - } - } else if ( memory ) { - list = []; - } else { - self.disable(); - } - } - }, - // Actual Callbacks object - self = { - // Add a callback or a collection of callbacks to the list - add: function() { - if ( list ) { - // First, we save the current length - var start = list.length; - (function add( args ) { - jQuery.each( args, function( _, arg ) { - var type = jQuery.type( arg ); - if ( type === "function" ) { - if ( !options.unique || !self.has( arg ) ) { - list.push( arg ); - } - } else if ( arg && arg.length && type !== "string" ) { - // Inspect recursively - add( arg ); - } - }); - })( arguments ); - // Do we need to add the callbacks to the - // current firing batch? - if ( firing ) { - firingLength = list.length; - // With memory, if we're not firing then - // we should call right away - } else if ( memory ) { - firingStart = start; - fire( memory ); - } - } - return this; - }, - // Remove a callback from the list - remove: function() { - if ( list ) { - jQuery.each( arguments, function( _, arg ) { - var index; - while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { - list.splice( index, 1 ); - // Handle firing indexes - if ( firing ) { - if ( index <= firingLength ) { - firingLength--; - } - if ( index <= firingIndex ) { - firingIndex--; - } - } - } - }); - } - return this; - }, - // Check if a given callback is in the list. - // If no argument is given, return whether or not list has callbacks attached. - has: function( fn ) { - return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length ); - }, - // Remove all callbacks from the list - empty: function() { - list = []; - firingLength = 0; - return this; - }, - // Have the list do nothing anymore - disable: function() { - list = stack = memory = undefined; - return this; - }, - // Is it disabled? - disabled: function() { - return !list; - }, - // Lock the list in its current state - lock: function() { - stack = undefined; - if ( !memory ) { - self.disable(); - } - return this; - }, - // Is it locked? - locked: function() { - return !stack; - }, - // Call all callbacks with the given context and arguments - fireWith: function( context, args ) { - if ( list && ( !fired || stack ) ) { - args = args || []; - args = [ context, args.slice ? args.slice() : args ]; - if ( firing ) { - stack.push( args ); - } else { - fire( args ); - } - } - return this; - }, - // Call all the callbacks with the given arguments - fire: function() { - self.fireWith( this, arguments ); - return this; - }, - // To know if the callbacks have already been called at least once - fired: function() { - return !!fired; - } - }; - - return self; -}; - - -jQuery.extend({ - - Deferred: function( func ) { - var tuples = [ - // action, add listener, listener list, final state - [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], - [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], - [ "notify", "progress", jQuery.Callbacks("memory") ] - ], - state = "pending", - promise = { - state: function() { - return state; - }, - always: function() { - deferred.done( arguments ).fail( arguments ); - return this; - }, - then: function( /* fnDone, fnFail, fnProgress */ ) { - var fns = arguments; - return jQuery.Deferred(function( newDefer ) { - jQuery.each( tuples, function( i, tuple ) { - var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; - // deferred[ done | fail | progress ] for forwarding actions to newDefer - deferred[ tuple[1] ](function() { - var returned = fn && fn.apply( this, arguments ); - if ( returned && jQuery.isFunction( returned.promise ) ) { - returned.promise() - .done( newDefer.resolve ) - .fail( newDefer.reject ) - .progress( newDefer.notify ); - } else { - newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments ); - } - }); - }); - fns = null; - }).promise(); - }, - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - return obj != null ? jQuery.extend( obj, promise ) : promise; - } - }, - deferred = {}; - - // Keep pipe for back-compat - promise.pipe = promise.then; - - // Add list-specific methods - jQuery.each( tuples, function( i, tuple ) { - var list = tuple[ 2 ], - stateString = tuple[ 3 ]; - - // promise[ done | fail | progress ] = list.add - promise[ tuple[1] ] = list.add; - - // Handle state - if ( stateString ) { - list.add(function() { - // state = [ resolved | rejected ] - state = stateString; - - // [ reject_list | resolve_list ].disable; progress_list.lock - }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); - } - - // deferred[ resolve | reject | notify ] - deferred[ tuple[0] ] = function() { - deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments ); - return this; - }; - deferred[ tuple[0] + "With" ] = list.fireWith; - }); - - // Make the deferred a promise - promise.promise( deferred ); - - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - - // All done! - return deferred; - }, - - // Deferred helper - when: function( subordinate /* , ..., subordinateN */ ) { - var i = 0, - resolveValues = slice.call( arguments ), - length = resolveValues.length, - - // the count of uncompleted subordinates - remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, - - // the master Deferred. If resolveValues consist of only a single Deferred, just use that. - deferred = remaining === 1 ? subordinate : jQuery.Deferred(), - - // Update function for both resolve and progress values - updateFunc = function( i, contexts, values ) { - return function( value ) { - contexts[ i ] = this; - values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; - if ( values === progressValues ) { - deferred.notifyWith( contexts, values ); - - } else if ( !(--remaining) ) { - deferred.resolveWith( contexts, values ); - } - }; - }, - - progressValues, progressContexts, resolveContexts; - - // add listeners to Deferred subordinates; treat others as resolved - if ( length > 1 ) { - progressValues = new Array( length ); - progressContexts = new Array( length ); - resolveContexts = new Array( length ); - for ( ; i < length; i++ ) { - if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { - resolveValues[ i ].promise() - .done( updateFunc( i, resolveContexts, resolveValues ) ) - .fail( deferred.reject ) - .progress( updateFunc( i, progressContexts, progressValues ) ); - } else { - --remaining; - } - } - } - - // if we're not waiting on anything, resolve the master - if ( !remaining ) { - deferred.resolveWith( resolveContexts, resolveValues ); - } - - return deferred.promise(); - } -}); - - -// The deferred used on DOM ready -var readyList; - -jQuery.fn.ready = function( fn ) { - // Add the callback - jQuery.ready.promise().done( fn ); - - return this; -}; - -jQuery.extend({ - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // A counter to track how many items to wait for before - // the ready event fires. See #6781 - readyWait: 1, - - // Hold (or release) the ready event - holdReady: function( hold ) { - if ( hold ) { - jQuery.readyWait++; - } else { - jQuery.ready( true ); - } - }, - - // Handle when the DOM is ready - ready: function( wait ) { - - // Abort if there are pending holds or we're already ready - if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { - return; - } - - // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). - if ( !document.body ) { - return setTimeout( jQuery.ready ); - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If a normal DOM Ready event fired, decrement, and wait if need be - if ( wait !== true && --jQuery.readyWait > 0 ) { - return; - } - - // If there are functions bound, to execute - readyList.resolveWith( document, [ jQuery ] ); - - // Trigger any bound ready events - if ( jQuery.fn.triggerHandler ) { - jQuery( document ).triggerHandler( "ready" ); - jQuery( document ).off( "ready" ); - } - } -}); - -/** - * Clean-up method for dom ready events - */ -function detach() { - if ( document.addEventListener ) { - document.removeEventListener( "DOMContentLoaded", completed, false ); - window.removeEventListener( "load", completed, false ); - - } else { - document.detachEvent( "onreadystatechange", completed ); - window.detachEvent( "onload", completed ); - } -} - -/** - * The ready event handler and self cleanup method - */ -function completed() { - // readyState === "complete" is good enough for us to call the dom ready in oldIE - if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) { - detach(); - jQuery.ready(); - } -} - -jQuery.ready.promise = function( obj ) { - if ( !readyList ) { - - readyList = jQuery.Deferred(); - - // Catch cases where $(document).ready() is called after the browser event has already occurred. - // we once tried to use readyState "interactive" here, but it caused issues like the one - // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 - if ( document.readyState === "complete" ) { - // Handle it asynchronously to allow scripts the opportunity to delay ready - setTimeout( jQuery.ready ); - - // Standards-based browsers support DOMContentLoaded - } else if ( document.addEventListener ) { - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", completed, false ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", completed, false ); - - // If IE event model is used - } else { - // Ensure firing before onload, maybe late but safe also for iframes - document.attachEvent( "onreadystatechange", completed ); - - // A fallback to window.onload, that will always work - window.attachEvent( "onload", completed ); - - // If IE and not a frame - // continually check to see if the document is ready - var top = false; - - try { - top = window.frameElement == null && document.documentElement; - } catch(e) {} - - if ( top && top.doScroll ) { - (function doScrollCheck() { - if ( !jQuery.isReady ) { - - try { - // Use the trick by Diego Perini - // http://javascript.nwbox.com/IEContentLoaded/ - top.doScroll("left"); - } catch(e) { - return setTimeout( doScrollCheck, 50 ); - } - - // detach all dom ready events - detach(); - - // and execute any waiting functions - jQuery.ready(); - } - })(); - } - } - } - return readyList.promise( obj ); -}; - - -var strundefined = typeof undefined; - - - -// Support: IE<9 -// Iteration over object's inherited properties before its own -var i; -for ( i in jQuery( support ) ) { - break; -} -support.ownLast = i !== "0"; - -// Note: most support tests are defined in their respective modules. -// false until the test is run -support.inlineBlockNeedsLayout = false; - -// Execute ASAP in case we need to set body.style.zoom -jQuery(function() { - // Minified: var a,b,c,d - var val, div, body, container; - - body = document.getElementsByTagName( "body" )[ 0 ]; - if ( !body || !body.style ) { - // Return for frameset docs that don't have a body - return; - } - - // Setup - div = document.createElement( "div" ); - container = document.createElement( "div" ); - container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px"; - body.appendChild( container ).appendChild( div ); - - if ( typeof div.style.zoom !== strundefined ) { - // Support: IE<8 - // Check if natively block-level elements act like inline-block - // elements when setting their display to 'inline' and giving - // them layout - div.style.cssText = "display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1"; - - support.inlineBlockNeedsLayout = val = div.offsetWidth === 3; - if ( val ) { - // Prevent IE 6 from affecting layout for positioned elements #11048 - // Prevent IE from shrinking the body in IE 7 mode #12869 - // Support: IE<8 - body.style.zoom = 1; - } - } - - body.removeChild( container ); -}); - - - - -(function() { - var div = document.createElement( "div" ); - - // Execute the test only if not already executed in another module. - if (support.deleteExpando == null) { - // Support: IE<9 - support.deleteExpando = true; - try { - delete div.test; - } catch( e ) { - support.deleteExpando = false; - } - } - - // Null elements to avoid leaks in IE. - div = null; -})(); - - -/** - * Determines whether an object can have data - */ -jQuery.acceptData = function( elem ) { - var noData = jQuery.noData[ (elem.nodeName + " ").toLowerCase() ], - nodeType = +elem.nodeType || 1; - - // Do not set data on non-element DOM nodes because it will not be cleared (#8335). - return nodeType !== 1 && nodeType !== 9 ? - false : - - // Nodes accept data unless otherwise specified; rejection can be conditional - !noData || noData !== true && elem.getAttribute("classid") === noData; -}; - - -var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, - rmultiDash = /([A-Z])/g; - -function dataAttr( elem, key, data ) { - // If nothing was found internally, try to fetch any - // data from the HTML5 data-* attribute - if ( data === undefined && elem.nodeType === 1 ) { - - var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); - - data = elem.getAttribute( name ); - - if ( typeof data === "string" ) { - try { - data = data === "true" ? true : - data === "false" ? false : - data === "null" ? null : - // Only convert to a number if it doesn't change the string - +data + "" === data ? +data : - rbrace.test( data ) ? jQuery.parseJSON( data ) : - data; - } catch( e ) {} - - // Make sure we set the data so it isn't changed later - jQuery.data( elem, key, data ); - - } else { - data = undefined; - } - } - - return data; -} - -// checks a cache object for emptiness -function isEmptyDataObject( obj ) { - var name; - for ( name in obj ) { - - // if the public data object is empty, the private is still empty - if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { - continue; - } - if ( name !== "toJSON" ) { - return false; - } - } - - return true; -} - -function internalData( elem, name, data, pvt /* Internal Use Only */ ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var ret, thisCache, - internalKey = jQuery.expando, - - // We have to handle DOM nodes and JS objects differently because IE6-7 - // can't GC object references properly across the DOM-JS boundary - isNode = elem.nodeType, - - // Only DOM nodes need the global jQuery cache; JS object data is - // attached directly to the object so GC can occur automatically - cache = isNode ? jQuery.cache : elem, - - // Only defining an ID for JS objects if its cache already exists allows - // the code to shortcut on the same path as a DOM node with no cache - id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; - - // Avoid doing any more work than we need to when trying to get data on an - // object that has no data at all - if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && data === undefined && typeof name === "string" ) { - return; - } - - if ( !id ) { - // Only DOM nodes need a new unique ID for each element since their data - // ends up in the global cache - if ( isNode ) { - id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++; - } else { - id = internalKey; - } - } - - if ( !cache[ id ] ) { - // Avoid exposing jQuery metadata on plain JS objects when the object - // is serialized using JSON.stringify - cache[ id ] = isNode ? {} : { toJSON: jQuery.noop }; - } - - // An object can be passed to jQuery.data instead of a key/value pair; this gets - // shallow copied over onto the existing cache - if ( typeof name === "object" || typeof name === "function" ) { - if ( pvt ) { - cache[ id ] = jQuery.extend( cache[ id ], name ); - } else { - cache[ id ].data = jQuery.extend( cache[ id ].data, name ); - } - } - - thisCache = cache[ id ]; - - // jQuery data() is stored in a separate object inside the object's internal data - // cache in order to avoid key collisions between internal data and user-defined - // data. - if ( !pvt ) { - if ( !thisCache.data ) { - thisCache.data = {}; - } - - thisCache = thisCache.data; - } - - if ( data !== undefined ) { - thisCache[ jQuery.camelCase( name ) ] = data; - } - - // Check for both converted-to-camel and non-converted data property names - // If a data property was specified - if ( typeof name === "string" ) { - - // First Try to find as-is property data - ret = thisCache[ name ]; - - // Test for null|undefined property data - if ( ret == null ) { - - // Try to find the camelCased property - ret = thisCache[ jQuery.camelCase( name ) ]; - } - } else { - ret = thisCache; - } - - return ret; -} - -function internalRemoveData( elem, name, pvt ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var thisCache, i, - isNode = elem.nodeType, - - // See jQuery.data for more information - cache = isNode ? jQuery.cache : elem, - id = isNode ? elem[ jQuery.expando ] : jQuery.expando; - - // If there is already no cache entry for this object, there is no - // purpose in continuing - if ( !cache[ id ] ) { - return; - } - - if ( name ) { - - thisCache = pvt ? cache[ id ] : cache[ id ].data; - - if ( thisCache ) { - - // Support array or space separated string names for data keys - if ( !jQuery.isArray( name ) ) { - - // try the string as a key before any manipulation - if ( name in thisCache ) { - name = [ name ]; - } else { - - // split the camel cased version by spaces unless a key with the spaces exists - name = jQuery.camelCase( name ); - if ( name in thisCache ) { - name = [ name ]; - } else { - name = name.split(" "); - } - } - } else { - // If "name" is an array of keys... - // When data is initially created, via ("key", "val") signature, - // keys will be converted to camelCase. - // Since there is no way to tell _how_ a key was added, remove - // both plain key and camelCase key. #12786 - // This will only penalize the array argument path. - name = name.concat( jQuery.map( name, jQuery.camelCase ) ); - } - - i = name.length; - while ( i-- ) { - delete thisCache[ name[i] ]; - } - - // If there is no data left in the cache, we want to continue - // and let the cache object itself get destroyed - if ( pvt ? !isEmptyDataObject(thisCache) : !jQuery.isEmptyObject(thisCache) ) { - return; - } - } - } - - // See jQuery.data for more information - if ( !pvt ) { - delete cache[ id ].data; - - // Don't destroy the parent cache unless the internal data object - // had been the only thing left in it - if ( !isEmptyDataObject( cache[ id ] ) ) { - return; - } - } - - // Destroy the cache - if ( isNode ) { - jQuery.cleanData( [ elem ], true ); - - // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) - /* jshint eqeqeq: false */ - } else if ( support.deleteExpando || cache != cache.window ) { - /* jshint eqeqeq: true */ - delete cache[ id ]; - - // When all else fails, null - } else { - cache[ id ] = null; - } -} - -jQuery.extend({ - cache: {}, - - // The following elements (space-suffixed to avoid Object.prototype collisions) - // throw uncatchable exceptions if you attempt to set expando properties - noData: { - "applet ": true, - "embed ": true, - // ...but Flash objects (which have this classid) *can* handle expandos - "object ": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" - }, - - hasData: function( elem ) { - elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; - return !!elem && !isEmptyDataObject( elem ); - }, - - data: function( elem, name, data ) { - return internalData( elem, name, data ); - }, - - removeData: function( elem, name ) { - return internalRemoveData( elem, name ); - }, - - // For internal use only. - _data: function( elem, name, data ) { - return internalData( elem, name, data, true ); - }, - - _removeData: function( elem, name ) { - return internalRemoveData( elem, name, true ); - } -}); - -jQuery.fn.extend({ - data: function( key, value ) { - var i, name, data, - elem = this[0], - attrs = elem && elem.attributes; - - // Special expections of .data basically thwart jQuery.access, - // so implement the relevant behavior ourselves - - // Gets all values - if ( key === undefined ) { - if ( this.length ) { - data = jQuery.data( elem ); - - if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { - i = attrs.length; - while ( i-- ) { - - // Support: IE11+ - // The attrs elements can be null (#14894) - if ( attrs[ i ] ) { - name = attrs[ i ].name; - if ( name.indexOf( "data-" ) === 0 ) { - name = jQuery.camelCase( name.slice(5) ); - dataAttr( elem, name, data[ name ] ); - } - } - } - jQuery._data( elem, "parsedAttrs", true ); - } - } - - return data; - } - - // Sets multiple values - if ( typeof key === "object" ) { - return this.each(function() { - jQuery.data( this, key ); - }); - } - - return arguments.length > 1 ? - - // Sets one value - this.each(function() { - jQuery.data( this, key, value ); - }) : - - // Gets one value - // Try to fetch any internally stored data first - elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined; - }, - - removeData: function( key ) { - return this.each(function() { - jQuery.removeData( this, key ); - }); - } -}); - - -jQuery.extend({ - queue: function( elem, type, data ) { - var queue; - - if ( elem ) { - type = ( type || "fx" ) + "queue"; - queue = jQuery._data( elem, type ); - - // Speed up dequeue by getting out quickly if this is just a lookup - if ( data ) { - if ( !queue || jQuery.isArray(data) ) { - queue = jQuery._data( elem, type, jQuery.makeArray(data) ); - } else { - queue.push( data ); - } - } - return queue || []; - } - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), - startLength = queue.length, - fn = queue.shift(), - hooks = jQuery._queueHooks( elem, type ), - next = function() { - jQuery.dequeue( elem, type ); - }; - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - startLength--; - } - - if ( fn ) { - - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift( "inprogress" ); - } - - // clear up the last queue stop function - delete hooks.stop; - fn.call( elem, next, hooks ); - } - - if ( !startLength && hooks ) { - hooks.empty.fire(); - } - }, - - // not intended for public consumption - generates a queueHooks object, or returns the current one - _queueHooks: function( elem, type ) { - var key = type + "queueHooks"; - return jQuery._data( elem, key ) || jQuery._data( elem, key, { - empty: jQuery.Callbacks("once memory").add(function() { - jQuery._removeData( elem, type + "queue" ); - jQuery._removeData( elem, key ); - }) - }); - } -}); - -jQuery.fn.extend({ - queue: function( type, data ) { - var setter = 2; - - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - setter--; - } - - if ( arguments.length < setter ) { - return jQuery.queue( this[0], type ); - } - - return data === undefined ? - this : - this.each(function() { - var queue = jQuery.queue( this, type, data ); - - // ensure a hooks for this queue - jQuery._queueHooks( this, type ); - - if ( type === "fx" && queue[0] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - }); - }, - dequeue: function( type ) { - return this.each(function() { - jQuery.dequeue( this, type ); - }); - }, - clearQueue: function( type ) { - return this.queue( type || "fx", [] ); - }, - // Get a promise resolved when queues of a certain type - // are emptied (fx is the type by default) - promise: function( type, obj ) { - var tmp, - count = 1, - defer = jQuery.Deferred(), - elements = this, - i = this.length, - resolve = function() { - if ( !( --count ) ) { - defer.resolveWith( elements, [ elements ] ); - } - }; - - if ( typeof type !== "string" ) { - obj = type; - type = undefined; - } - type = type || "fx"; - - while ( i-- ) { - tmp = jQuery._data( elements[ i ], type + "queueHooks" ); - if ( tmp && tmp.empty ) { - count++; - tmp.empty.add( resolve ); - } - } - resolve(); - return defer.promise( obj ); - } -}); -var pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source; - -var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; - -var isHidden = function( elem, el ) { - // isHidden might be called from jQuery#filter function; - // in that case, element will be second argument - elem = el || elem; - return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); - }; - - - -// Multifunctional method to get and set values of a collection -// The value/s can optionally be executed if it's a function -var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) { - var i = 0, - length = elems.length, - bulk = key == null; - - // Sets many values - if ( jQuery.type( key ) === "object" ) { - chainable = true; - for ( i in key ) { - jQuery.access( elems, fn, i, key[i], true, emptyGet, raw ); - } - - // Sets one value - } else if ( value !== undefined ) { - chainable = true; - - if ( !jQuery.isFunction( value ) ) { - raw = true; - } - - if ( bulk ) { - // Bulk operations run against the entire set - if ( raw ) { - fn.call( elems, value ); - fn = null; - - // ...except when executing function values - } else { - bulk = fn; - fn = function( elem, key, value ) { - return bulk.call( jQuery( elem ), value ); - }; - } - } - - if ( fn ) { - for ( ; i < length; i++ ) { - fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) ); - } - } - } - - return chainable ? - elems : - - // Gets - bulk ? - fn.call( elems ) : - length ? fn( elems[0], key ) : emptyGet; -}; -var rcheckableType = (/^(?:checkbox|radio)$/i); - - - -(function() { - // Minified: var a,b,c - var input = document.createElement( "input" ), - div = document.createElement( "div" ), - fragment = document.createDocumentFragment(); - - // Setup - div.innerHTML = "
a"; - - // IE strips leading whitespace when .innerHTML is used - support.leadingWhitespace = div.firstChild.nodeType === 3; - - // Make sure that tbody elements aren't automatically inserted - // IE will insert them into empty tables - support.tbody = !div.getElementsByTagName( "tbody" ).length; - - // Make sure that link elements get serialized correctly by innerHTML - // This requires a wrapper element in IE - support.htmlSerialize = !!div.getElementsByTagName( "link" ).length; - - // Makes sure cloning an html5 element does not cause problems - // Where outerHTML is undefined, this still works - support.html5Clone = - document.createElement( "nav" ).cloneNode( true ).outerHTML !== "<:nav>"; - - // Check if a disconnected checkbox will retain its checked - // value of true after appended to the DOM (IE6/7) - input.type = "checkbox"; - input.checked = true; - fragment.appendChild( input ); - support.appendChecked = input.checked; - - // Make sure textarea (and checkbox) defaultValue is properly cloned - // Support: IE6-IE11+ - div.innerHTML = ""; - support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; - - // #11217 - WebKit loses check when the name is after the checked attribute - fragment.appendChild( div ); - div.innerHTML = ""; - - // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3 - // old WebKit doesn't clone checked state correctly in fragments - support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; - - // Support: IE<9 - // Opera does not clone events (and typeof div.attachEvent === undefined). - // IE9-10 clones events bound via attachEvent, but they don't trigger with .click() - support.noCloneEvent = true; - if ( div.attachEvent ) { - div.attachEvent( "onclick", function() { - support.noCloneEvent = false; - }); - - div.cloneNode( true ).click(); - } - - // Execute the test only if not already executed in another module. - if (support.deleteExpando == null) { - // Support: IE<9 - support.deleteExpando = true; - try { - delete div.test; - } catch( e ) { - support.deleteExpando = false; - } - } -})(); - - -(function() { - var i, eventName, - div = document.createElement( "div" ); - - // Support: IE<9 (lack submit/change bubble), Firefox 23+ (lack focusin event) - for ( i in { submit: true, change: true, focusin: true }) { - eventName = "on" + i; - - if ( !(support[ i + "Bubbles" ] = eventName in window) ) { - // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP) - div.setAttribute( eventName, "t" ); - support[ i + "Bubbles" ] = div.attributes[ eventName ].expando === false; - } - } - - // Null elements to avoid leaks in IE. - div = null; -})(); - - -var rformElems = /^(?:input|select|textarea)$/i, - rkeyEvent = /^key/, - rmouseEvent = /^(?:mouse|pointer|contextmenu)|click/, - rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, - rtypenamespace = /^([^.]*)(?:\.(.+)|)$/; - -function returnTrue() { - return true; -} - -function returnFalse() { - return false; -} - -function safeActiveElement() { - try { - return document.activeElement; - } catch ( err ) { } -} - -/* - * Helper functions for managing events -- not part of the public interface. - * Props to Dean Edwards' addEvent library for many of the ideas. - */ -jQuery.event = { - - global: {}, - - add: function( elem, types, handler, data, selector ) { - var tmp, events, t, handleObjIn, - special, eventHandle, handleObj, - handlers, type, namespaces, origType, - elemData = jQuery._data( elem ); - - // Don't attach events to noData or text/comment nodes (but allow plain objects) - if ( !elemData ) { - return; - } - - // Caller can pass in an object of custom data in lieu of the handler - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; - selector = handleObjIn.selector; - } - - // Make sure that the handler has a unique ID, used to find/remove it later - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // Init the element's event structure and main handler, if this is the first - if ( !(events = elemData.events) ) { - events = elemData.events = {}; - } - if ( !(eventHandle = elemData.handle) ) { - eventHandle = elemData.handle = function( e ) { - // Discard the second event of a jQuery.event.trigger() and - // when an event is called after a page has unloaded - return typeof jQuery !== strundefined && (!e || jQuery.event.triggered !== e.type) ? - jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : - undefined; - }; - // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events - eventHandle.elem = elem; - } - - // Handle multiple events separated by a space - types = ( types || "" ).match( rnotwhite ) || [ "" ]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[t] ) || []; - type = origType = tmp[1]; - namespaces = ( tmp[2] || "" ).split( "." ).sort(); - - // There *must* be a type, no attaching namespace-only handlers - if ( !type ) { - continue; - } - - // If event changes its type, use the special event handlers for the changed type - special = jQuery.event.special[ type ] || {}; - - // If selector defined, determine special event api type, otherwise given type - type = ( selector ? special.delegateType : special.bindType ) || type; - - // Update special based on newly reset type - special = jQuery.event.special[ type ] || {}; - - // handleObj is passed to all event handlers - handleObj = jQuery.extend({ - type: type, - origType: origType, - data: data, - handler: handler, - guid: handler.guid, - selector: selector, - needsContext: selector && jQuery.expr.match.needsContext.test( selector ), - namespace: namespaces.join(".") - }, handleObjIn ); - - // Init the event handler queue if we're the first - if ( !(handlers = events[ type ]) ) { - handlers = events[ type ] = []; - handlers.delegateCount = 0; - - // Only use addEventListener/attachEvent if the special events handler returns false - if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { - // Bind the global event handler to the element - if ( elem.addEventListener ) { - elem.addEventListener( type, eventHandle, false ); - - } else if ( elem.attachEvent ) { - elem.attachEvent( "on" + type, eventHandle ); - } - } - } - - if ( special.add ) { - special.add.call( elem, handleObj ); - - if ( !handleObj.handler.guid ) { - handleObj.handler.guid = handler.guid; - } - } - - // Add to the element's handler list, delegates in front - if ( selector ) { - handlers.splice( handlers.delegateCount++, 0, handleObj ); - } else { - handlers.push( handleObj ); - } - - // Keep track of which events have ever been used, for event optimization - jQuery.event.global[ type ] = true; - } - - // Nullify elem to prevent memory leaks in IE - elem = null; - }, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, selector, mappedTypes ) { - var j, handleObj, tmp, - origCount, t, events, - special, handlers, type, - namespaces, origType, - elemData = jQuery.hasData( elem ) && jQuery._data( elem ); - - if ( !elemData || !(events = elemData.events) ) { - return; - } - - // Once for each type.namespace in types; type may be omitted - types = ( types || "" ).match( rnotwhite ) || [ "" ]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[t] ) || []; - type = origType = tmp[1]; - namespaces = ( tmp[2] || "" ).split( "." ).sort(); - - // Unbind all events (on this namespace, if provided) for the element - if ( !type ) { - for ( type in events ) { - jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); - } - continue; - } - - special = jQuery.event.special[ type ] || {}; - type = ( selector ? special.delegateType : special.bindType ) || type; - handlers = events[ type ] || []; - tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ); - - // Remove matching events - origCount = j = handlers.length; - while ( j-- ) { - handleObj = handlers[ j ]; - - if ( ( mappedTypes || origType === handleObj.origType ) && - ( !handler || handler.guid === handleObj.guid ) && - ( !tmp || tmp.test( handleObj.namespace ) ) && - ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { - handlers.splice( j, 1 ); - - if ( handleObj.selector ) { - handlers.delegateCount--; - } - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } - } - } - - // Remove generic event handler if we removed something and no more handlers exist - // (avoids potential for endless recursion during removal of special event handlers) - if ( origCount && !handlers.length ) { - if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { - jQuery.removeEvent( elem, type, elemData.handle ); - } - - delete events[ type ]; - } - } - - // Remove the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - delete elemData.handle; - - // removeData also checks for emptiness and clears the expando if empty - // so use it instead of delete - jQuery._removeData( elem, "events" ); - } - }, - - trigger: function( event, data, elem, onlyHandlers ) { - var handle, ontype, cur, - bubbleType, special, tmp, i, - eventPath = [ elem || document ], - type = hasOwn.call( event, "type" ) ? event.type : event, - namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : []; - - cur = tmp = elem = elem || document; - - // Don't do events on text and comment nodes - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - // focus/blur morphs to focusin/out; ensure we're not firing them right now - if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { - return; - } - - if ( type.indexOf(".") >= 0 ) { - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split("."); - type = namespaces.shift(); - namespaces.sort(); - } - ontype = type.indexOf(":") < 0 && "on" + type; - - // Caller can pass in a jQuery.Event object, Object, or just an event type string - event = event[ jQuery.expando ] ? - event : - new jQuery.Event( type, typeof event === "object" && event ); - - // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) - event.isTrigger = onlyHandlers ? 2 : 3; - event.namespace = namespaces.join("."); - event.namespace_re = event.namespace ? - new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) : - null; - - // Clean up the event in case it is being reused - event.result = undefined; - if ( !event.target ) { - event.target = elem; - } - - // Clone any incoming data and prepend the event, creating the handler arg list - data = data == null ? - [ event ] : - jQuery.makeArray( data, [ event ] ); - - // Allow special events to draw outside the lines - special = jQuery.event.special[ type ] || {}; - if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { - return; - } - - // Determine event propagation path in advance, per W3C events spec (#9951) - // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) - if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { - - bubbleType = special.delegateType || type; - if ( !rfocusMorph.test( bubbleType + type ) ) { - cur = cur.parentNode; - } - for ( ; cur; cur = cur.parentNode ) { - eventPath.push( cur ); - tmp = cur; - } - - // Only add window if we got to document (e.g., not plain obj or detached DOM) - if ( tmp === (elem.ownerDocument || document) ) { - eventPath.push( tmp.defaultView || tmp.parentWindow || window ); - } - } - - // Fire handlers on the event path - i = 0; - while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) { - - event.type = i > 1 ? - bubbleType : - special.bindType || type; - - // jQuery handler - handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); - if ( handle ) { - handle.apply( cur, data ); - } - - // Native handler - handle = ontype && cur[ ontype ]; - if ( handle && handle.apply && jQuery.acceptData( cur ) ) { - event.result = handle.apply( cur, data ); - if ( event.result === false ) { - event.preventDefault(); - } - } - } - event.type = type; - - // If nobody prevented the default action, do it now - if ( !onlyHandlers && !event.isDefaultPrevented() ) { - - if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) && - jQuery.acceptData( elem ) ) { - - // Call a native DOM method on the target with the same name name as the event. - // Can't use an .isFunction() check here because IE6/7 fails that test. - // Don't do default actions on window, that's where global variables be (#6170) - if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) { - - // Don't re-trigger an onFOO event when we call its FOO() method - tmp = elem[ ontype ]; - - if ( tmp ) { - elem[ ontype ] = null; - } - - // Prevent re-triggering of the same event, since we already bubbled it above - jQuery.event.triggered = type; - try { - elem[ type ](); - } catch ( e ) { - // IE<9 dies on focus/blur to hidden element (#1486,#12518) - // only reproducible on winXP IE8 native, not IE9 in IE8 mode - } - jQuery.event.triggered = undefined; - - if ( tmp ) { - elem[ ontype ] = tmp; - } - } - } - } - - return event.result; - }, - - dispatch: function( event ) { - - // Make a writable jQuery.Event from the native event object - event = jQuery.event.fix( event ); - - var i, ret, handleObj, matched, j, - handlerQueue = [], - args = slice.call( arguments ), - handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [], - special = jQuery.event.special[ event.type ] || {}; - - // Use the fix-ed jQuery.Event rather than the (read-only) native event - args[0] = event; - event.delegateTarget = this; - - // Call the preDispatch hook for the mapped type, and let it bail if desired - if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { - return; - } - - // Determine handlers - handlerQueue = jQuery.event.handlers.call( this, event, handlers ); - - // Run delegates first; they may want to stop propagation beneath us - i = 0; - while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) { - event.currentTarget = matched.elem; - - j = 0; - while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) { - - // Triggered event must either 1) have no namespace, or - // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). - if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) { - - event.handleObj = handleObj; - event.data = handleObj.data; - - ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) - .apply( matched.elem, args ); - - if ( ret !== undefined ) { - if ( (event.result = ret) === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - } - } - } - - // Call the postDispatch hook for the mapped type - if ( special.postDispatch ) { - special.postDispatch.call( this, event ); - } - - return event.result; - }, - - handlers: function( event, handlers ) { - var sel, handleObj, matches, i, - handlerQueue = [], - delegateCount = handlers.delegateCount, - cur = event.target; - - // Find delegate handlers - // Black-hole SVG instance trees (#13180) - // Avoid non-left-click bubbling in Firefox (#3861) - if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) { - - /* jshint eqeqeq: false */ - for ( ; cur != this; cur = cur.parentNode || this ) { - /* jshint eqeqeq: true */ - - // Don't check non-elements (#13208) - // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) - if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) { - matches = []; - for ( i = 0; i < delegateCount; i++ ) { - handleObj = handlers[ i ]; - - // Don't conflict with Object.prototype properties (#13203) - sel = handleObj.selector + " "; - - if ( matches[ sel ] === undefined ) { - matches[ sel ] = handleObj.needsContext ? - jQuery( sel, this ).index( cur ) >= 0 : - jQuery.find( sel, this, null, [ cur ] ).length; - } - if ( matches[ sel ] ) { - matches.push( handleObj ); - } - } - if ( matches.length ) { - handlerQueue.push({ elem: cur, handlers: matches }); - } - } - } - } - - // Add the remaining (directly-bound) handlers - if ( delegateCount < handlers.length ) { - handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) }); - } - - return handlerQueue; - }, - - fix: function( event ) { - if ( event[ jQuery.expando ] ) { - return event; - } - - // Create a writable copy of the event object and normalize some properties - var i, prop, copy, - type = event.type, - originalEvent = event, - fixHook = this.fixHooks[ type ]; - - if ( !fixHook ) { - this.fixHooks[ type ] = fixHook = - rmouseEvent.test( type ) ? this.mouseHooks : - rkeyEvent.test( type ) ? this.keyHooks : - {}; - } - copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; - - event = new jQuery.Event( originalEvent ); - - i = copy.length; - while ( i-- ) { - prop = copy[ i ]; - event[ prop ] = originalEvent[ prop ]; - } - - // Support: IE<9 - // Fix target property (#1925) - if ( !event.target ) { - event.target = originalEvent.srcElement || document; - } - - // Support: Chrome 23+, Safari? - // Target should not be a text node (#504, #13143) - if ( event.target.nodeType === 3 ) { - event.target = event.target.parentNode; - } - - // Support: IE<9 - // For mouse/key events, metaKey==false if it's undefined (#3368, #11328) - event.metaKey = !!event.metaKey; - - return fixHook.filter ? fixHook.filter( event, originalEvent ) : event; - }, - - // Includes some event props shared by KeyEvent and MouseEvent - props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), - - fixHooks: {}, - - keyHooks: { - props: "char charCode key keyCode".split(" "), - filter: function( event, original ) { - - // Add which for key events - if ( event.which == null ) { - event.which = original.charCode != null ? original.charCode : original.keyCode; - } - - return event; - } - }, - - mouseHooks: { - props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), - filter: function( event, original ) { - var body, eventDoc, doc, - button = original.button, - fromElement = original.fromElement; - - // Calculate pageX/Y if missing and clientX/Y available - if ( event.pageX == null && original.clientX != null ) { - eventDoc = event.target.ownerDocument || document; - doc = eventDoc.documentElement; - body = eventDoc.body; - - event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); - event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); - } - - // Add relatedTarget, if necessary - if ( !event.relatedTarget && fromElement ) { - event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - // Note: button is not normalized, so don't use it - if ( !event.which && button !== undefined ) { - event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); - } - - return event; - } - }, - - special: { - load: { - // Prevent triggered image.load events from bubbling to window.load - noBubble: true - }, - focus: { - // Fire native event if possible so blur/focus sequence is correct - trigger: function() { - if ( this !== safeActiveElement() && this.focus ) { - try { - this.focus(); - return false; - } catch ( e ) { - // Support: IE<9 - // If we error on focus to hidden element (#1486, #12518), - // let .trigger() run the handlers - } - } - }, - delegateType: "focusin" - }, - blur: { - trigger: function() { - if ( this === safeActiveElement() && this.blur ) { - this.blur(); - return false; - } - }, - delegateType: "focusout" - }, - click: { - // For checkbox, fire native event so checked state will be right - trigger: function() { - if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) { - this.click(); - return false; - } - }, - - // For cross-browser consistency, don't fire native .click() on links - _default: function( event ) { - return jQuery.nodeName( event.target, "a" ); - } - }, - - beforeunload: { - postDispatch: function( event ) { - - // Support: Firefox 20+ - // Firefox doesn't alert if the returnValue field is not set. - if ( event.result !== undefined && event.originalEvent ) { - event.originalEvent.returnValue = event.result; - } - } - } - }, - - simulate: function( type, elem, event, bubble ) { - // Piggyback on a donor event to simulate a different one. - // Fake originalEvent to avoid donor's stopPropagation, but if the - // simulated event prevents default then we do the same on the donor. - var e = jQuery.extend( - new jQuery.Event(), - event, - { - type: type, - isSimulated: true, - originalEvent: {} - } - ); - if ( bubble ) { - jQuery.event.trigger( e, null, elem ); - } else { - jQuery.event.dispatch.call( elem, e ); - } - if ( e.isDefaultPrevented() ) { - event.preventDefault(); - } - } -}; - -jQuery.removeEvent = document.removeEventListener ? - function( elem, type, handle ) { - if ( elem.removeEventListener ) { - elem.removeEventListener( type, handle, false ); - } - } : - function( elem, type, handle ) { - var name = "on" + type; - - if ( elem.detachEvent ) { - - // #8545, #7054, preventing memory leaks for custom events in IE6-8 - // detachEvent needed property on element, by name of that event, to properly expose it to GC - if ( typeof elem[ name ] === strundefined ) { - elem[ name ] = null; - } - - elem.detachEvent( name, handle ); - } - }; - -jQuery.Event = function( src, props ) { - // Allow instantiation without the 'new' keyword - if ( !(this instanceof jQuery.Event) ) { - return new jQuery.Event( src, props ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - - // Events bubbling up the document may have been marked as prevented - // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = src.defaultPrevented || - src.defaultPrevented === undefined && - // Support: IE < 9, Android < 4.0 - src.returnValue === false ? - returnTrue : - returnFalse; - - // Event type - } else { - this.type = src; - } - - // Put explicitly provided properties onto the event object - if ( props ) { - jQuery.extend( this, props ); - } - - // Create a timestamp if incoming event doesn't have one - this.timeStamp = src && src.timeStamp || jQuery.now(); - - // Mark it as fixed - this[ jQuery.expando ] = true; -}; - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse, - - preventDefault: function() { - var e = this.originalEvent; - - this.isDefaultPrevented = returnTrue; - if ( !e ) { - return; - } - - // If preventDefault exists, run it on the original event - if ( e.preventDefault ) { - e.preventDefault(); - - // Support: IE - // Otherwise set the returnValue property of the original event to false - } else { - e.returnValue = false; - } - }, - stopPropagation: function() { - var e = this.originalEvent; - - this.isPropagationStopped = returnTrue; - if ( !e ) { - return; - } - // If stopPropagation exists, run it on the original event - if ( e.stopPropagation ) { - e.stopPropagation(); - } - - // Support: IE - // Set the cancelBubble property of the original event to true - e.cancelBubble = true; - }, - stopImmediatePropagation: function() { - var e = this.originalEvent; - - this.isImmediatePropagationStopped = returnTrue; - - if ( e && e.stopImmediatePropagation ) { - e.stopImmediatePropagation(); - } - - this.stopPropagation(); - } -}; - -// Create mouseenter/leave events using mouseover/out and event-time checks -jQuery.each({ - mouseenter: "mouseover", - mouseleave: "mouseout", - pointerenter: "pointerover", - pointerleave: "pointerout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - delegateType: fix, - bindType: fix, - - handle: function( event ) { - var ret, - target = this, - related = event.relatedTarget, - handleObj = event.handleObj; - - // For mousenter/leave call the handler if related is outside the target. - // NB: No relatedTarget if the mouse left/entered the browser window - if ( !related || (related !== target && !jQuery.contains( target, related )) ) { - event.type = handleObj.origType; - ret = handleObj.handler.apply( this, arguments ); - event.type = fix; - } - return ret; - } - }; -}); - -// IE submit delegation -if ( !support.submitBubbles ) { - - jQuery.event.special.submit = { - setup: function() { - // Only need this for delegated form submit events - if ( jQuery.nodeName( this, "form" ) ) { - return false; - } - - // Lazy-add a submit handler when a descendant form may potentially be submitted - jQuery.event.add( this, "click._submit keypress._submit", function( e ) { - // Node name check avoids a VML-related crash in IE (#9807) - var elem = e.target, - form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; - if ( form && !jQuery._data( form, "submitBubbles" ) ) { - jQuery.event.add( form, "submit._submit", function( event ) { - event._submit_bubble = true; - }); - jQuery._data( form, "submitBubbles", true ); - } - }); - // return undefined since we don't need an event listener - }, - - postDispatch: function( event ) { - // If form was submitted by the user, bubble the event up the tree - if ( event._submit_bubble ) { - delete event._submit_bubble; - if ( this.parentNode && !event.isTrigger ) { - jQuery.event.simulate( "submit", this.parentNode, event, true ); - } - } - }, - - teardown: function() { - // Only need this for delegated form submit events - if ( jQuery.nodeName( this, "form" ) ) { - return false; - } - - // Remove delegated handlers; cleanData eventually reaps submit handlers attached above - jQuery.event.remove( this, "._submit" ); - } - }; -} - -// IE change delegation and checkbox/radio fix -if ( !support.changeBubbles ) { - - jQuery.event.special.change = { - - setup: function() { - - if ( rformElems.test( this.nodeName ) ) { - // IE doesn't fire change on a check/radio until blur; trigger it on click - // after a propertychange. Eat the blur-change in special.change.handle. - // This still fires onchange a second time for check/radio after blur. - if ( this.type === "checkbox" || this.type === "radio" ) { - jQuery.event.add( this, "propertychange._change", function( event ) { - if ( event.originalEvent.propertyName === "checked" ) { - this._just_changed = true; - } - }); - jQuery.event.add( this, "click._change", function( event ) { - if ( this._just_changed && !event.isTrigger ) { - this._just_changed = false; - } - // Allow triggered, simulated change events (#11500) - jQuery.event.simulate( "change", this, event, true ); - }); - } - return false; - } - // Delegated event; lazy-add a change handler on descendant inputs - jQuery.event.add( this, "beforeactivate._change", function( e ) { - var elem = e.target; - - if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) { - jQuery.event.add( elem, "change._change", function( event ) { - if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { - jQuery.event.simulate( "change", this.parentNode, event, true ); - } - }); - jQuery._data( elem, "changeBubbles", true ); - } - }); - }, - - handle: function( event ) { - var elem = event.target; - - // Swallow native change events from checkbox/radio, we already triggered them above - if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { - return event.handleObj.handler.apply( this, arguments ); - } - }, - - teardown: function() { - jQuery.event.remove( this, "._change" ); - - return !rformElems.test( this.nodeName ); - } - }; -} - -// Create "bubbling" focus and blur events -if ( !support.focusinBubbles ) { - jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { - - // Attach a single capturing handler on the document while someone wants focusin/focusout - var handler = function( event ) { - jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); - }; - - jQuery.event.special[ fix ] = { - setup: function() { - var doc = this.ownerDocument || this, - attaches = jQuery._data( doc, fix ); - - if ( !attaches ) { - doc.addEventListener( orig, handler, true ); - } - jQuery._data( doc, fix, ( attaches || 0 ) + 1 ); - }, - teardown: function() { - var doc = this.ownerDocument || this, - attaches = jQuery._data( doc, fix ) - 1; - - if ( !attaches ) { - doc.removeEventListener( orig, handler, true ); - jQuery._removeData( doc, fix ); - } else { - jQuery._data( doc, fix, attaches ); - } - } - }; - }); -} - -jQuery.fn.extend({ - - on: function( types, selector, data, fn, /*INTERNAL*/ one ) { - var type, origFn; - - // Types can be a map of types/handlers - if ( typeof types === "object" ) { - // ( types-Object, selector, data ) - if ( typeof selector !== "string" ) { - // ( types-Object, data ) - data = data || selector; - selector = undefined; - } - for ( type in types ) { - this.on( type, selector, data, types[ type ], one ); - } - return this; - } - - if ( data == null && fn == null ) { - // ( types, fn ) - fn = selector; - data = selector = undefined; - } else if ( fn == null ) { - if ( typeof selector === "string" ) { - // ( types, selector, fn ) - fn = data; - data = undefined; - } else { - // ( types, data, fn ) - fn = data; - data = selector; - selector = undefined; - } - } - if ( fn === false ) { - fn = returnFalse; - } else if ( !fn ) { - return this; - } - - if ( one === 1 ) { - origFn = fn; - fn = function( event ) { - // Can use an empty set, since event contains the info - jQuery().off( event ); - return origFn.apply( this, arguments ); - }; - // Use same guid so caller can remove using origFn - fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); - } - return this.each( function() { - jQuery.event.add( this, types, fn, data, selector ); - }); - }, - one: function( types, selector, data, fn ) { - return this.on( types, selector, data, fn, 1 ); - }, - off: function( types, selector, fn ) { - var handleObj, type; - if ( types && types.preventDefault && types.handleObj ) { - // ( event ) dispatched jQuery.Event - handleObj = types.handleObj; - jQuery( types.delegateTarget ).off( - handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, - handleObj.selector, - handleObj.handler - ); - return this; - } - if ( typeof types === "object" ) { - // ( types-object [, selector] ) - for ( type in types ) { - this.off( type, selector, types[ type ] ); - } - return this; - } - if ( selector === false || typeof selector === "function" ) { - // ( types [, fn] ) - fn = selector; - selector = undefined; - } - if ( fn === false ) { - fn = returnFalse; - } - return this.each(function() { - jQuery.event.remove( this, types, fn, selector ); - }); - }, - - trigger: function( type, data ) { - return this.each(function() { - jQuery.event.trigger( type, data, this ); - }); - }, - triggerHandler: function( type, data ) { - var elem = this[0]; - if ( elem ) { - return jQuery.event.trigger( type, data, elem, true ); - } - } -}); - - -function createSafeFragment( document ) { - var list = nodeNames.split( "|" ), - safeFrag = document.createDocumentFragment(); - - if ( safeFrag.createElement ) { - while ( list.length ) { - safeFrag.createElement( - list.pop() - ); - } - } - return safeFrag; -} - -var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + - "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", - rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, - rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"), - rleadingWhitespace = /^\s+/, - rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, - rtagName = /<([\w:]+)/, - rtbody = /\s*$/g, - - // We have to close these tags to support XHTML (#13200) - wrapMap = { - option: [ 1, "" ], - legend: [ 1, "
", "
" ], - area: [ 1, "", "" ], - param: [ 1, "", "" ], - thead: [ 1, "", "
" ], - tr: [ 2, "", "
" ], - col: [ 2, "", "
" ], - td: [ 3, "", "
" ], - - // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, - // unless wrapped in a div with non-breaking characters in front of it. - _default: support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X
", "
" ] - }, - safeFragment = createSafeFragment( document ), - fragmentDiv = safeFragment.appendChild( document.createElement("div") ); - -wrapMap.optgroup = wrapMap.option; -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - -function getAll( context, tag ) { - var elems, elem, - i = 0, - found = typeof context.getElementsByTagName !== strundefined ? context.getElementsByTagName( tag || "*" ) : - typeof context.querySelectorAll !== strundefined ? context.querySelectorAll( tag || "*" ) : - undefined; - - if ( !found ) { - for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) { - if ( !tag || jQuery.nodeName( elem, tag ) ) { - found.push( elem ); - } else { - jQuery.merge( found, getAll( elem, tag ) ); - } - } - } - - return tag === undefined || tag && jQuery.nodeName( context, tag ) ? - jQuery.merge( [ context ], found ) : - found; -} - -// Used in buildFragment, fixes the defaultChecked property -function fixDefaultChecked( elem ) { - if ( rcheckableType.test( elem.type ) ) { - elem.defaultChecked = elem.checked; - } -} - -// Support: IE<8 -// Manipulating tables requires a tbody -function manipulationTarget( elem, content ) { - return jQuery.nodeName( elem, "table" ) && - jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ? - - elem.getElementsByTagName("tbody")[0] || - elem.appendChild( elem.ownerDocument.createElement("tbody") ) : - elem; -} - -// Replace/restore the type attribute of script elements for safe DOM manipulation -function disableScript( elem ) { - elem.type = (jQuery.find.attr( elem, "type" ) !== null) + "/" + elem.type; - return elem; -} -function restoreScript( elem ) { - var match = rscriptTypeMasked.exec( elem.type ); - if ( match ) { - elem.type = match[1]; - } else { - elem.removeAttribute("type"); - } - return elem; -} - -// Mark scripts as having already been evaluated -function setGlobalEval( elems, refElements ) { - var elem, - i = 0; - for ( ; (elem = elems[i]) != null; i++ ) { - jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) ); - } -} - -function cloneCopyEvent( src, dest ) { - - if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { - return; - } - - var type, i, l, - oldData = jQuery._data( src ), - curData = jQuery._data( dest, oldData ), - events = oldData.events; - - if ( events ) { - delete curData.handle; - curData.events = {}; - - for ( type in events ) { - for ( i = 0, l = events[ type ].length; i < l; i++ ) { - jQuery.event.add( dest, type, events[ type ][ i ] ); - } - } - } - - // make the cloned public data object a copy from the original - if ( curData.data ) { - curData.data = jQuery.extend( {}, curData.data ); - } -} - -function fixCloneNodeIssues( src, dest ) { - var nodeName, e, data; - - // We do not need to do anything for non-Elements - if ( dest.nodeType !== 1 ) { - return; - } - - nodeName = dest.nodeName.toLowerCase(); - - // IE6-8 copies events bound via attachEvent when using cloneNode. - if ( !support.noCloneEvent && dest[ jQuery.expando ] ) { - data = jQuery._data( dest ); - - for ( e in data.events ) { - jQuery.removeEvent( dest, e, data.handle ); - } - - // Event data gets referenced instead of copied if the expando gets copied too - dest.removeAttribute( jQuery.expando ); - } - - // IE blanks contents when cloning scripts, and tries to evaluate newly-set text - if ( nodeName === "script" && dest.text !== src.text ) { - disableScript( dest ).text = src.text; - restoreScript( dest ); - - // IE6-10 improperly clones children of object elements using classid. - // IE10 throws NoModificationAllowedError if parent is null, #12132. - } else if ( nodeName === "object" ) { - if ( dest.parentNode ) { - dest.outerHTML = src.outerHTML; - } - - // This path appears unavoidable for IE9. When cloning an object - // element in IE9, the outerHTML strategy above is not sufficient. - // If the src has innerHTML and the destination does not, - // copy the src.innerHTML into the dest.innerHTML. #10324 - if ( support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) { - dest.innerHTML = src.innerHTML; - } - - } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) { - // IE6-8 fails to persist the checked state of a cloned checkbox - // or radio button. Worse, IE6-7 fail to give the cloned element - // a checked appearance if the defaultChecked value isn't also set - - dest.defaultChecked = dest.checked = src.checked; - - // IE6-7 get confused and end up setting the value of a cloned - // checkbox/radio button to an empty string instead of "on" - if ( dest.value !== src.value ) { - dest.value = src.value; - } - - // IE6-8 fails to return the selected option to the default selected - // state when cloning options - } else if ( nodeName === "option" ) { - dest.defaultSelected = dest.selected = src.defaultSelected; - - // IE6-8 fails to set the defaultValue to the correct value when - // cloning other types of input fields - } else if ( nodeName === "input" || nodeName === "textarea" ) { - dest.defaultValue = src.defaultValue; - } -} - -jQuery.extend({ - clone: function( elem, dataAndEvents, deepDataAndEvents ) { - var destElements, node, clone, i, srcElements, - inPage = jQuery.contains( elem.ownerDocument, elem ); - - if ( support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { - clone = elem.cloneNode( true ); - - // IE<=8 does not properly clone detached, unknown element nodes - } else { - fragmentDiv.innerHTML = elem.outerHTML; - fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); - } - - if ( (!support.noCloneEvent || !support.noCloneChecked) && - (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { - - // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 - destElements = getAll( clone ); - srcElements = getAll( elem ); - - // Fix all IE cloning issues - for ( i = 0; (node = srcElements[i]) != null; ++i ) { - // Ensure that the destination node is not null; Fixes #9587 - if ( destElements[i] ) { - fixCloneNodeIssues( node, destElements[i] ); - } - } - } - - // Copy the events from the original to the clone - if ( dataAndEvents ) { - if ( deepDataAndEvents ) { - srcElements = srcElements || getAll( elem ); - destElements = destElements || getAll( clone ); - - for ( i = 0; (node = srcElements[i]) != null; i++ ) { - cloneCopyEvent( node, destElements[i] ); - } - } else { - cloneCopyEvent( elem, clone ); - } - } - - // Preserve script evaluation history - destElements = getAll( clone, "script" ); - if ( destElements.length > 0 ) { - setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); - } - - destElements = srcElements = node = null; - - // Return the cloned set - return clone; - }, - - buildFragment: function( elems, context, scripts, selection ) { - var j, elem, contains, - tmp, tag, tbody, wrap, - l = elems.length, - - // Ensure a safe fragment - safe = createSafeFragment( context ), - - nodes = [], - i = 0; - - for ( ; i < l; i++ ) { - elem = elems[ i ]; - - if ( elem || elem === 0 ) { - - // Add nodes directly - if ( jQuery.type( elem ) === "object" ) { - jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); - - // Convert non-html into a text node - } else if ( !rhtml.test( elem ) ) { - nodes.push( context.createTextNode( elem ) ); - - // Convert html into DOM nodes - } else { - tmp = tmp || safe.appendChild( context.createElement("div") ); - - // Deserialize a standard representation - tag = (rtagName.exec( elem ) || [ "", "" ])[ 1 ].toLowerCase(); - wrap = wrapMap[ tag ] || wrapMap._default; - - tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1>" ) + wrap[2]; - - // Descend through wrappers to the right content - j = wrap[0]; - while ( j-- ) { - tmp = tmp.lastChild; - } - - // Manually add leading whitespace removed by IE - if ( !support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { - nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) ); - } - - // Remove IE's autoinserted from table fragments - if ( !support.tbody ) { - - // String was a , *may* have spurious - elem = tag === "table" && !rtbody.test( elem ) ? - tmp.firstChild : - - // String was a bare or - wrap[1] === "
" && !rtbody.test( elem ) ? - tmp : - 0; - - j = elem && elem.childNodes.length; - while ( j-- ) { - if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) { - elem.removeChild( tbody ); - } - } - } - - jQuery.merge( nodes, tmp.childNodes ); - - // Fix #12392 for WebKit and IE > 9 - tmp.textContent = ""; - - // Fix #12392 for oldIE - while ( tmp.firstChild ) { - tmp.removeChild( tmp.firstChild ); - } - - // Remember the top-level container for proper cleanup - tmp = safe.lastChild; - } - } - } - - // Fix #11356: Clear elements from fragment - if ( tmp ) { - safe.removeChild( tmp ); - } - - // Reset defaultChecked for any radios and checkboxes - // about to be appended to the DOM in IE 6/7 (#8060) - if ( !support.appendChecked ) { - jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked ); - } - - i = 0; - while ( (elem = nodes[ i++ ]) ) { - - // #4087 - If origin and destination elements are the same, and this is - // that element, do not do anything - if ( selection && jQuery.inArray( elem, selection ) !== -1 ) { - continue; - } - - contains = jQuery.contains( elem.ownerDocument, elem ); - - // Append to fragment - tmp = getAll( safe.appendChild( elem ), "script" ); - - // Preserve script evaluation history - if ( contains ) { - setGlobalEval( tmp ); - } - - // Capture executables - if ( scripts ) { - j = 0; - while ( (elem = tmp[ j++ ]) ) { - if ( rscriptType.test( elem.type || "" ) ) { - scripts.push( elem ); - } - } - } - } - - tmp = null; - - return safe; - }, - - cleanData: function( elems, /* internal */ acceptData ) { - var elem, type, id, data, - i = 0, - internalKey = jQuery.expando, - cache = jQuery.cache, - deleteExpando = support.deleteExpando, - special = jQuery.event.special; - - for ( ; (elem = elems[i]) != null; i++ ) { - if ( acceptData || jQuery.acceptData( elem ) ) { - - id = elem[ internalKey ]; - data = id && cache[ id ]; - - if ( data ) { - if ( data.events ) { - for ( type in data.events ) { - if ( special[ type ] ) { - jQuery.event.remove( elem, type ); - - // This is a shortcut to avoid jQuery.event.remove's overhead - } else { - jQuery.removeEvent( elem, type, data.handle ); - } - } - } - - // Remove cache only if it was not already removed by jQuery.event.remove - if ( cache[ id ] ) { - - delete cache[ id ]; - - // IE does not allow us to delete expando properties from nodes, - // nor does it have a removeAttribute function on Document nodes; - // we must handle all of these cases - if ( deleteExpando ) { - delete elem[ internalKey ]; - - } else if ( typeof elem.removeAttribute !== strundefined ) { - elem.removeAttribute( internalKey ); - - } else { - elem[ internalKey ] = null; - } - - deletedIds.push( id ); - } - } - } - } - } -}); - -jQuery.fn.extend({ - text: function( value ) { - return access( this, function( value ) { - return value === undefined ? - jQuery.text( this ) : - this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); - }, null, value, arguments.length ); - }, - - append: function() { - return this.domManip( arguments, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - var target = manipulationTarget( this, elem ); - target.appendChild( elem ); - } - }); - }, - - prepend: function() { - return this.domManip( arguments, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - var target = manipulationTarget( this, elem ); - target.insertBefore( elem, target.firstChild ); - } - }); - }, - - before: function() { - return this.domManip( arguments, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this ); - } - }); - }, - - after: function() { - return this.domManip( arguments, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this.nextSibling ); - } - }); - }, - - remove: function( selector, keepData /* Internal Use Only */ ) { - var elem, - elems = selector ? jQuery.filter( selector, this ) : this, - i = 0; - - for ( ; (elem = elems[i]) != null; i++ ) { - - if ( !keepData && elem.nodeType === 1 ) { - jQuery.cleanData( getAll( elem ) ); - } - - if ( elem.parentNode ) { - if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) { - setGlobalEval( getAll( elem, "script" ) ); - } - elem.parentNode.removeChild( elem ); - } - } - - return this; - }, - - empty: function() { - var elem, - i = 0; - - for ( ; (elem = this[i]) != null; i++ ) { - // Remove element nodes and prevent memory leaks - if ( elem.nodeType === 1 ) { - jQuery.cleanData( getAll( elem, false ) ); - } - - // Remove any remaining nodes - while ( elem.firstChild ) { - elem.removeChild( elem.firstChild ); - } - - // If this is a select, ensure that it displays empty (#12336) - // Support: IE<9 - if ( elem.options && jQuery.nodeName( elem, "select" ) ) { - elem.options.length = 0; - } - } - - return this; - }, - - clone: function( dataAndEvents, deepDataAndEvents ) { - dataAndEvents = dataAndEvents == null ? false : dataAndEvents; - deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; - - return this.map(function() { - return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); - }); - }, - - html: function( value ) { - return access( this, function( value ) { - var elem = this[ 0 ] || {}, - i = 0, - l = this.length; - - if ( value === undefined ) { - return elem.nodeType === 1 ? - elem.innerHTML.replace( rinlinejQuery, "" ) : - undefined; - } - - // See if we can take a shortcut and just use innerHTML - if ( typeof value === "string" && !rnoInnerhtml.test( value ) && - ( support.htmlSerialize || !rnoshimcache.test( value ) ) && - ( support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && - !wrapMap[ (rtagName.exec( value ) || [ "", "" ])[ 1 ].toLowerCase() ] ) { - - value = value.replace( rxhtmlTag, "<$1>" ); - - try { - for (; i < l; i++ ) { - // Remove element nodes and prevent memory leaks - elem = this[i] || {}; - if ( elem.nodeType === 1 ) { - jQuery.cleanData( getAll( elem, false ) ); - elem.innerHTML = value; - } - } - - elem = 0; - - // If using innerHTML throws an exception, use the fallback method - } catch(e) {} - } - - if ( elem ) { - this.empty().append( value ); - } - }, null, value, arguments.length ); - }, - - replaceWith: function() { - var arg = arguments[ 0 ]; - - // Make the changes, replacing each context element with the new content - this.domManip( arguments, function( elem ) { - arg = this.parentNode; - - jQuery.cleanData( getAll( this ) ); - - if ( arg ) { - arg.replaceChild( elem, this ); - } - }); - - // Force removal if there was no new content (e.g., from empty arguments) - return arg && (arg.length || arg.nodeType) ? this : this.remove(); - }, - - detach: function( selector ) { - return this.remove( selector, true ); - }, - - domManip: function( args, callback ) { - - // Flatten any nested arrays - args = concat.apply( [], args ); - - var first, node, hasScripts, - scripts, doc, fragment, - i = 0, - l = this.length, - set = this, - iNoClone = l - 1, - value = args[0], - isFunction = jQuery.isFunction( value ); - - // We can't cloneNode fragments that contain checked, in WebKit - if ( isFunction || - ( l > 1 && typeof value === "string" && - !support.checkClone && rchecked.test( value ) ) ) { - return this.each(function( index ) { - var self = set.eq( index ); - if ( isFunction ) { - args[0] = value.call( this, index, self.html() ); - } - self.domManip( args, callback ); - }); - } - - if ( l ) { - fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this ); - first = fragment.firstChild; - - if ( fragment.childNodes.length === 1 ) { - fragment = first; - } - - if ( first ) { - scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); - hasScripts = scripts.length; - - // Use the original fragment for the last item instead of the first because it can end up - // being emptied incorrectly in certain situations (#8070). - for ( ; i < l; i++ ) { - node = fragment; - - if ( i !== iNoClone ) { - node = jQuery.clone( node, true, true ); - - // Keep references to cloned scripts for later restoration - if ( hasScripts ) { - jQuery.merge( scripts, getAll( node, "script" ) ); - } - } - - callback.call( this[i], node, i ); - } - - if ( hasScripts ) { - doc = scripts[ scripts.length - 1 ].ownerDocument; - - // Reenable scripts - jQuery.map( scripts, restoreScript ); - - // Evaluate executable scripts on first document insertion - for ( i = 0; i < hasScripts; i++ ) { - node = scripts[ i ]; - if ( rscriptType.test( node.type || "" ) && - !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) { - - if ( node.src ) { - // Optional AJAX dependency, but won't run scripts if not present - if ( jQuery._evalUrl ) { - jQuery._evalUrl( node.src ); - } - } else { - jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) ); - } - } - } - } - - // Fix #11809: Avoid leaking memory - fragment = first = null; - } - } - - return this; - } -}); - -jQuery.each({ - appendTo: "append", - prependTo: "prepend", - insertBefore: "before", - insertAfter: "after", - replaceAll: "replaceWith" -}, function( name, original ) { - jQuery.fn[ name ] = function( selector ) { - var elems, - i = 0, - ret = [], - insert = jQuery( selector ), - last = insert.length - 1; - - for ( ; i <= last; i++ ) { - elems = i === last ? this : this.clone(true); - jQuery( insert[i] )[ original ]( elems ); - - // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get() - push.apply( ret, elems.get() ); - } - - return this.pushStack( ret ); - }; -}); - - -var iframe, - elemdisplay = {}; - -/** - * Retrieve the actual display of a element - * @param {String} name nodeName of the element - * @param {Object} doc Document object - */ -// Called only from within defaultDisplay -function actualDisplay( name, doc ) { - var style, - elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ), - - // getDefaultComputedStyle might be reliably used only on attached element - display = window.getDefaultComputedStyle && ( style = window.getDefaultComputedStyle( elem[ 0 ] ) ) ? - - // Use of this method is a temporary fix (more like optmization) until something better comes along, - // since it was removed from specification and supported only in FF - style.display : jQuery.css( elem[ 0 ], "display" ); - - // We don't have any data stored on the element, - // so use "detach" method as fast way to get rid of the element - elem.detach(); - - return display; -} - -/** - * Try to determine the default display value of an element - * @param {String} nodeName - */ -function defaultDisplay( nodeName ) { - var doc = document, - display = elemdisplay[ nodeName ]; - - if ( !display ) { - display = actualDisplay( nodeName, doc ); - - // If the simple way fails, read from inside an iframe - if ( display === "none" || !display ) { - - // Use the already-created iframe if possible - iframe = (iframe || jQuery( "