From 4d9ccfc52864f7c6d9cc226e068bba43dbd7fd27 Mon Sep 17 00:00:00 2001 From: p31729568 Date: Wed, 10 Jul 2019 09:41:02 +0800 Subject: [PATCH 01/42] project package feature --- app/api/mobile/api.rb | 17 ++- app/api/mobile/apis/project_packages.rb | 144 ++++++++++++++++++ app/api/mobile/entities/project_package.rb | 65 ++++++++ app/controllers/account_controller.rb | 20 ++- .../project_package_applies_controller.rb | 46 ++++++ app/helpers/application_helper.rb | 3 + app/models/bidding_user.rb | 20 +++ app/models/project_package.rb | 76 +++++++++ app/models/project_package_apply.rb | 21 +++ app/models/tiding.rb | 21 +++ app/models/user.rb | 3 + app/models/verification_code.rb | 4 + .../project_packages/agree_apply_service.rb | 36 +++++ .../project_packages/apply_publish_service.rb | 31 ++++ .../project_packages/bidding_service.rb | 29 ++++ .../project_packages/end_bidding_service.rb | 26 ++++ .../project_packages/refuse_apply_service.rb | 38 +++++ app/services/project_packages/save_service.rb | 66 ++++++++ .../project_packages/win_bidding_service.rb | 47 ++++++ app/views/layouts/base_management.html.erb | 1 + .../_project_package_apply_list.html.erb | 76 +++++++++ .../project_package_applies/index.html.erb | 120 +++++++++++++++ .../project_package_applies/index.js.erb | 30 ++++ config/routes.rb | 7 + .../20190709004039_create_project_packages.rb | 28 ++++ .../20190709010031_create_bidding_users.rb | 12 ++ ...09023928_create_project_package_applies.rb | 14 ++ 27 files changed, 998 insertions(+), 3 deletions(-) create mode 100644 app/api/mobile/apis/project_packages.rb create mode 100644 app/api/mobile/entities/project_package.rb create mode 100644 app/controllers/managements/project_package_applies_controller.rb create mode 100644 app/models/bidding_user.rb create mode 100644 app/models/project_package.rb create mode 100644 app/models/project_package_apply.rb create mode 100644 app/services/project_packages/agree_apply_service.rb create mode 100644 app/services/project_packages/apply_publish_service.rb create mode 100644 app/services/project_packages/bidding_service.rb create mode 100644 app/services/project_packages/end_bidding_service.rb create mode 100644 app/services/project_packages/refuse_apply_service.rb create mode 100644 app/services/project_packages/save_service.rb create mode 100644 app/services/project_packages/win_bidding_service.rb create mode 100644 app/views/managements/project_package_applies/_project_package_apply_list.html.erb create mode 100644 app/views/managements/project_package_applies/index.html.erb create mode 100644 app/views/managements/project_package_applies/index.js.erb create mode 100644 db/migrate/20190709004039_create_project_packages.rb create mode 100644 db/migrate/20190709010031_create_bidding_users.rb create mode 100644 db/migrate/20190709023928_create_project_package_applies.rb diff --git a/app/api/mobile/api.rb b/app/api/mobile/api.rb index 894ba099..8d01bb5b 100644 --- a/app/api/mobile/api.rb +++ b/app/api/mobile/api.rb @@ -166,6 +166,21 @@ module Mobile return user if user nil end + + def paginate(objs) + page = params[:page].to_i <= 0 ? 1 : params[:page].to_i + per_page = params[:per_page].to_i > 0 ? params[:per_page].to_i : 20 + + Kaminari.paginate_array(objs).page(page).per(per_page) + end + + def render_ok(data = {}) + { status: 0, message: 'success' }.merge(data) + end + + def render_error(message) + { status: -1, message: message } + end end mount Apis::Auth @@ -197,7 +212,7 @@ module Mobile mount Apis::Ecloud mount Apis::Cnmooc - + mount Apis::ProjectPackages # add_swagger_documentation ({host: 'educoder.0bug.info', api_version: 'v1', base_path: '/api'}) if Rails.env.development? add_swagger_documentation ({api_version: 'v1', base_path: '/api'}) if Rails.env.development? diff --git a/app/api/mobile/apis/project_packages.rb b/app/api/mobile/apis/project_packages.rb new file mode 100644 index 00000000..d5c4143f --- /dev/null +++ b/app/api/mobile/apis/project_packages.rb @@ -0,0 +1,144 @@ +module Mobile + module Apis + class ProjectPackages < Grape::API + helpers do + def current_package + @_current_package ||= ProjectPackage.find(params[:id]) + end + + def symbolize_params + params.to_hash.symbolize_keys + end + end + + resources :project_packages do + desc 'project packages index' + params do + optional :category, type: String, desc: '类型' + optional :keyword, type: String, desc: '搜索关键字' + optional :sort_by, type: String, desc: '排序' + optional :page, type: Integer, desc: '页数' + optional :per_page, type: Integer, desc: '分页大小' + end + get do + packages = ProjectPackage.where(status: %w(published bidding_ended bidding_finished)) + + packages = packages.where(category: params[:category]) if params[:category].present? + + keyword = params[:keyword].to_s.strip + packages = packages.where('title LIKE ?', "%#{keyword}%") if keyword.present? + + count = packages.count + + if params[:sort_by] == 'price' + packages = packages.order('min_price desc') + else + packages = packages.order('published_at desc') + end + packages = paginate packages.includes(:creator, :attachments, bidding_users: :user) + + present :count, count + present :project_packages, packages, with: Mobile::Entities::ProjectPackage, type: :index, user: current_user + end + + + desc 'project package show' + params do + requires :id, type: Integer, desc: 'ID' + end + route_param :id do + get do + authenticate! + + present current_package, with: Mobile::Entities::ProjectPackage, type: :show, user: current_user + end + + resource :bidding_users do + desc 'user bidding' + params {} + post do + authenticate! + begin + ::ProjectPackages::BiddingService.new(current_package, current_user).call + render_ok + rescue ::ProjectPackages::BiddingService::Error => ex + render_error(ex.message) + end + end + + desc 'select bidding user win' + params do + requires :user_ids, type: Array[Integer], desc: '中标者用户ID数组' + end + post 'win' do + authenticate! + begin + package = current_user.project_packages.find(params[:id]) + ProjectPackages::WinBiddingService.new(package, symbolize_params).call + rescue ProjectPackages::WinBiddingService::Error =>ex + render_error(ex.message) + end + end + end + end + + + desc 'create project packages' + params do + requires :category, type: String, desc: '类型' + requires :title, type: String, desc: '标题' + requires :content, type: String, desc: '描述' + optional :attachment_ids, type: Array[Integer], desc: '附件ID数组' + requires :deadline_at, type: DateTime, desc: '截止日期' + requires :min_price, type: Float, desc: '最小费用' + optional :max_price, type: Float, desc: '最大费用' + requires :contact_name, type: String, desc: '联系人姓名' + requires :contact_phone, type: String, desc: '联系人手机号' + optional :code, type: String, desc: '验证码' + optional :publish, type: Boolean, desc: '是否申请发布' + end + post do + authenticate! + begin + package = current_user.project_packages.new + ::ProjectPackages::SaveService.new(package, symbolize_params).call + package.increment_visit_count! + render_ok + rescue ::ProjectPackages::SaveService::Error => ex + render_error(ex.message) + end + end + + + desc 'update project package' + params do + requires :id, type: Integer, desc: 'ID' + requires :category, type: String, desc: '类型' + requires :title, type: String, desc: '标题' + requires :content, type: String, desc: '描述' + optional :attachment_ids, type: Array[Integer], desc: '附件ID数组' + requires :deadline_at, type: DateTime, desc: '截止日期' + requires :min_price, type: Float, desc: '最小费用' + optional :max_price, type: Float, desc: '最大费用' + requires :contact_name, type: String, desc: '联系人姓名' + requires :contact_phone, type: String, desc: '联系人手机号' + optional :code, type: String, desc: '验证码' + optional :publish, type: Boolean, desc: '是否申请发布' + end + put ':id' do + authenticate! + begin + package = current_user.project_packages.find(params[:id]) + return render_error('该状态下不能编辑') unless package.editable? + + ::ProjectPackages::SaveService.new(package, symbolize_params).call + package.increment_visit_count! + render_ok + rescue ::ProjectPackages::SaveService::Error => ex + render_error(ex.message) + end + end + end + end + end +end diff --git a/app/api/mobile/entities/project_package.rb b/app/api/mobile/entities/project_package.rb new file mode 100644 index 00000000..fdf94a32 --- /dev/null +++ b/app/api/mobile/entities/project_package.rb @@ -0,0 +1,65 @@ +module Mobile + module Entities + class ProjectPackage < Grape::Entity + include ApplicationHelper + include ActionView::Helpers::NumberHelper + + expose :id + expose :title + expose :category + expose :status + expose :visit_count, if: { type: :index } + expose :bidding_users_count, if: { type: :index } + expose :min_price + expose :max_price + + expose :deadline_at do |package, _| + package.deadline_at.try(:utc).try(:iso8601) + end + expose :published_at do |package, _| + package.published_at.try(:utc).try(:iso8601) + end + + expose :can_bidding, if: { type: :show } do |package, opts| + package.can_bidding?(opts[:user]) + end + + expose :can_select_bidding_user, if: { type: :show } do |package, opts| + opts[:user].id == package.creator_id && !package.bidding_end? + end + + expose :creator, if: { type: :show } do |package, _| + { + id: package.creator.id, + login: package.creator.login, + name: package.creator.show_real_name, + avatar_url: "/images/#{url_to_avatar(package.creator)}" + } + end + + expose :attachments, if: { type: :show } do |package, _| + package.attachments.map do |attachment| + { + id: attachment.id, + title: attachment.title, + filesize: number_to_human_size(attachment.filesize), + url: "attachments/download/#{attachment.id}", + } + end + end + + expose :bidding_users, if: { type: :show } do |package, _| + package.bidding_users.map do |bidding_user| + user = bidding_user.user + { + id: user.id, + login: user.login, + name: user.name, + avatar_url: "/images/#{url_to_avatar(user)}", + status: bidding_user.status + } + end + end + end + end +end diff --git a/app/controllers/account_controller.rb b/app/controllers/account_controller.rb index 3368da12..7e474611 100644 --- a/app/controllers/account_controller.rb +++ b/app/controllers/account_controller.rb @@ -681,7 +681,7 @@ class AccountController < ApplicationController render :json => req end - # 发送验证码:type 1:注册手机验证码 2:找回密码手机验证码 3:找回密码邮箱验证码 4:绑定手机 5:绑定邮箱 6:手机验证码登录 7:邮箱验证码登录 8:邮箱注册验证码 + # 发送验证码:type 1:注册手机验证码 2:找回密码手机验证码 3:找回密码邮箱验证码 4:绑定手机 5:绑定邮箱 6:手机验证码登录 7:邮箱验证码登录 8:邮箱注册验证码 9:验证手机号有效 # 验证码是否有效 def valid_verification_code req = Hash.new(false) @@ -700,7 +700,7 @@ class AccountController < ApplicationController render :json => req end - # 发送验证码:type 1:注册手机验证码 2:找回密码手机验证码 3:找回密码邮箱验证码 4:绑定手机 5:绑定邮箱 6:手机验证码登录 7:邮箱验证码登录 8:邮箱注册验证码 + # 发送验证码:type 1:注册手机验证码 2:找回密码手机验证码 3:找回密码邮箱验证码 4:绑定手机 5:绑定邮箱 6:手机验证码登录 7:邮箱验证码登录 8:邮箱注册验证码 9:验证手机号有效 def get_verification_code code = %W(0 1 2 3 4 5 6 7 8 9) type = params[:type].to_i @@ -787,6 +787,22 @@ class AccountController < ApplicationController else req[:status] = 2 end + elsif params[:type] == 9 + if params[:value] =~ /^1\d{10}$/ + begin + verification_code = code.sample(6).join + status = Trustie::Sms.send(mobile: params[:value], code: verification_code) + if status == 0 + VerificationCode.create(:phone => params[:value], :status => 1, :code_type => type, :code => verification_code) + end + req[:msg] = code_msg status + rescue => e + Rails.logger.error "发送验证码出错: #{e}" + end + req[:status] = 1 + else + req[:status] = 2 + end else if params[:value] =~ /^[a-zA-Z0-9]+([._\\]*[a-z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/ if User.where(:mail => params[:value]).count > 0 diff --git a/app/controllers/managements/project_package_applies_controller.rb b/app/controllers/managements/project_package_applies_controller.rb new file mode 100644 index 00000000..6394b745 --- /dev/null +++ b/app/controllers/managements/project_package_applies_controller.rb @@ -0,0 +1,46 @@ +class Managements::ProjectPackageAppliesController < Managements::BaseController + before_filter :set_menu_type + + def index + applies = ProjectPackageApply.order('project_package_applies.updated_at desc') + + search = params[:search].to_s.strip + if search.present? + applies = applies.joins(:project_package).where('project_packages.title like :search', search: "%#{search}%") + end + + applies = applies.where(status: params[:status].presence || :pending) + + @applies = paginateHelper applies.includes(project_package: { creator: :user_extensions }) + + respond_to do |format| + format.js + format.html + end + end + + def agree + ProjectPackages::AgreeApplyService.new(current_apply).call + render json: { status: 0 } + rescue ProjectPackages::AgreeApplyService::Error => e + render json: { status: -1, message: e.message } + end + + def refuse + ProjectPackages::RefuseApplyService.new(current_apply, reason: params[:reason]).call + render json: { status: 0 } + rescue ProjectPackages::RefuseApplyService::Error => e + render json: { status: -1, message: e.message } + end + + private + + def current_apply + @_current_apply ||= ProjectPackageApply.find(params[:id]) + end + + def set_menu_type + @menu_type = 10 + @sub_type = 9 + end +end \ No newline at end of file diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index b65a2fa8..51825709 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -754,6 +754,7 @@ module ApplicationHelper when 6 then '实训课程发布' when 7 then '职业认证' when 8 then '教学案例发布' + when 9 then '众包需求发布' else '职业认证' end when 11 @@ -7453,6 +7454,8 @@ def tiding_url tiding my_account_path when 'Library' tiding.tiding_type == 'Apply' ? library_applies_path : library_path(tiding.container_id) + when 'ProjectPackage' + tiding.container.present? ? "/project_packages/#{tiding.container_id}" : 'javascript:void(0)' end end diff --git a/app/models/bidding_user.rb b/app/models/bidding_user.rb new file mode 100644 index 00000000..5869b6d4 --- /dev/null +++ b/app/models/bidding_user.rb @@ -0,0 +1,20 @@ +class BiddingUser < ActiveRecord::Base + include AASM + + belongs_to :user + belongs_to :project_package, counter_cache: true + + aasm(:status) do + state :pending, initiali: true + state :bidding_won + state :bidding_lost + + event :win do + transitions from: [:pending], to: :bid_won + end + + event :lose do + transitions from: [:pending], to: :bid_lost + end + end +end \ No newline at end of file diff --git a/app/models/project_package.rb b/app/models/project_package.rb new file mode 100644 index 00000000..b9b6ac46 --- /dev/null +++ b/app/models/project_package.rb @@ -0,0 +1,76 @@ +class ProjectPackage < ActiveRecord::Base + include AASM + + acts_as_attachable + + CATEGORY_VALUES = %w(front backend mobile database cloud_compute_and_big_data devops_and_test ai other) + + attr_accessible :title, :content, :category, :deadline_at, :contact_name, :contact_phone, :min_price, :max_price + + belongs_to :creator, class_name: 'User' + + has_many :project_package_applies, dependent: :destroy + has_one :process_project_package_apply, conditions: { status: :pending }, class_name: 'ProjectPackageApply' + + has_many :bidding_users, dependent: :delete_all + has_many :win_bidding_users, conditions: { status: :bidding_won }, class_name: 'BiddingUser' + has_many :lose_bidding_users, conditions: { status: :bidding_lost }, class_name: 'BiddingUser' + + has_many :attachments, as: :container, dependent: :destroy + + validates :category, presence: true, inclusion: { in: CATEGORY_VALUES } + validates :title, presence: true, length: { maximum: 60 } + validates :content, presence: true + validates :deadline_at, presence: true + validates :contact_name, presence: true, length: { maximum: 20 } + validates :contact_phone, presence: true, format: { with: /1\d{10}/ } + validates :min_price, numericality: { greater_than: 0 } + validates :max_price, numericality: { greater_than: ->(obj){ obj.min_price } }, allow_blank: true + + aasm(:status) do + state :pending, initiali: true + state :applying + state :refused + state :published + state :bidding_ended + state :bidding_finished + + event :apply do + transitions from: [:pending, :refused], to: :applying + end + + event :refuse do + transitions from: :applying, to: :refused + end + + event :publish do + transitions from: :applying, to: :published + end + + event :end_bidding do + transitions from: :published, to: :bidding_ended + end + + event :finish_bidding do + transitions from: [:bidding_ended], to: :bidding_finished + end + end + + def editable? + pending? || applying? || refused? + end + + def bidding_end? + flag = deadline_at < Time.now + end_bidding! if flag && can_end_bidding? + flag + end + + def can_bidding?(user) + published? && !bidding_end? && !bidding_users.exists?(user_id: user.id) + end + + def increment_visit_count! + ProjectPackage.connection.execute("update project_packages set visit_count = COALESCE(visit_count, 0) + 1 where id = #{id}") + end +end \ No newline at end of file diff --git a/app/models/project_package_apply.rb b/app/models/project_package_apply.rb new file mode 100644 index 00000000..06c7493f --- /dev/null +++ b/app/models/project_package_apply.rb @@ -0,0 +1,21 @@ +class ProjectPackageApply < ActiveRecord::Base + include AASM + + attr_accessible :project_package_id, :reason + + belongs_to :project_package + + aasm(:status) do + state :pending, initiali: true + state :refused + state :agreed + + event :refuse do + transitions from: :pending, to: :refused + end + + event :agree do + transitions from: :pending, to: :agreed + end + end +end \ No newline at end of file diff --git a/app/models/tiding.rb b/app/models/tiding.rb index 5107374e..986d9cef 100644 --- a/app/models/tiding.rb +++ b/app/models/tiding.rb @@ -365,6 +365,27 @@ class Tiding < ActiveRecord::Base elsif tiding_type == 'System' text = status == 1 ? "审核已通过" : "审核未通过,
原因:#{extra}" "你提交的发布教学案例申请:#{library.try(:title)},#{text}" + end + when 'ProjectPackage' + package = ProjectPackage.find_by_id(container_id) + case tiding_type + when 'Apply' then + "申请发布众包需求:#{package.try(:title)}" + when 'System' then + text = status == 1 ? "审核已通过" : "审核未通过,
原因:#{extra}" + "你提交的众包需求申请:#{package.try(:title)},#{text}" + when 'Created' then + "你创建了众包需求:#{package.try(:title)}" + when 'Destroyed' then + "你删除了众包需求:#{extra}" + when 'Bidding' then + "应征了你发布的众包任务:#{package.try(:title)}" + when 'BiddingEnd' then + "你发布的众包任务:#{package.try(:title)},已进入选标阶段,请尽快进行选择确认!" + when 'BiddingWon' then + "恭喜,你应征的众包任务:#{package.try(:title)},在评选环节中标了" + when 'BiddingLost' then + "很遗憾,你应征投稿的众包任务:#{package.try(:title)},未中标" end else logger.error "error type: 1" diff --git a/app/models/user.rb b/app/models/user.rb index c206d51e..b5545206 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -274,6 +274,9 @@ class User < Principal has_one :user_source + # 众包 + has_many :project_packages, foreign_key: :creator_id, dependent: :destroy + ## end # default_scope -> { includes(:user_extensions, :user_score) } diff --git a/app/models/verification_code.rb b/app/models/verification_code.rb index e3fefc83..4bc473b3 100644 --- a/app/models/verification_code.rb +++ b/app/models/verification_code.rb @@ -2,4 +2,8 @@ class VerificationCode < ActiveRecord::Base #status:发送状态 #code_type:发送类型:type 1:注册手机验证码 2:找回密码手机验证码 3:找回密码邮箱验证码 4:绑定手机 5:绑定邮箱 6:手机验证码登录 7:邮箱验证码登录 8:邮箱注册验证码 attr_accessible :code, :code_type, :email, :phone, :status + + def valid_code? + (Time.now.to_i - created_at.to_i) <= 10*60 + end end diff --git a/app/services/project_packages/agree_apply_service.rb b/app/services/project_packages/agree_apply_service.rb new file mode 100644 index 00000000..c8d8ebde --- /dev/null +++ b/app/services/project_packages/agree_apply_service.rb @@ -0,0 +1,36 @@ +class ProjectPackages::AgreeApplyService + Error = Class.new(StandardError) + + attr_reader :apply, :package + + def initialize(apply) + @apply = apply + @package = apply.project_package + end + + def call + raise Error, '该状态下不能进行此操作' unless apply.may_agree? && package.may_publish? + + ActiveRecord::Base.transaction do + apply.agree! + + # 发布 + package.publish + package.published_at = Time.now + package.save! + + # 消息 + send_agree_notify! + end + end + + private + def send_agree_notify! + Tiding.where(container_id: package.id, container_type: 'ProjectPackage', + tiding_type: 'Apply', status: 0).update_all(status: 1) + + Tiding.create!(user_id: package.creator_id, trigger_user_id: 1, + container_id: package.id, container_type: 'ProjectPackage', + tiding_type: 'System', status: 1) + end +end \ No newline at end of file diff --git a/app/services/project_packages/apply_publish_service.rb b/app/services/project_packages/apply_publish_service.rb new file mode 100644 index 00000000..45aee77b --- /dev/null +++ b/app/services/project_packages/apply_publish_service.rb @@ -0,0 +1,31 @@ +class ProjectPackages::ApplyPublishService + Error = Class.new(StandardError) + + attr_reader :package + + def initialize(package) + @package = package + end + + def call + return if package.applying? + + raise Error, '该状态下不能申请发布' if package.can_apply? + + ActiveRecord::Base.transaction do + package.apply! + + package.project_package_applies.create! + + send_project_package_apply_notify! + end + end + + private + + def send_project_package_apply_notify! + Tiding.create!(user_id: 1, trigger_user_id: package.creator_id, + container_id: package.id, container_type: 'ProjectPackage', + tiding_type: 'Apply', status: 0) + end +end diff --git a/app/services/project_packages/bidding_service.rb b/app/services/project_packages/bidding_service.rb new file mode 100644 index 00000000..9ad9ce4f --- /dev/null +++ b/app/services/project_packages/bidding_service.rb @@ -0,0 +1,29 @@ +class ProjectPackages::BiddingService + Error = Class.new(StandardError) + + attr_reader :package, :user + + def initialize(package, user) + @package = package + @user = user + end + + def call + raise Error, '竞标已截止' if package.bidding_end? + raise Error, '不能参与自己发布的竞标' if package.creator_id == user.id + raise Error, '您已参与竞标' if package.bidding_users.exists?(user_id: user.id) + + ActiveRecord::Base.transaction do + package.bidding_users.create!(user_id: user.id) + + send_bidding_notify! + end + end + + private + + def send_bidding_notify! + Tiding.create!(user_id: package.creator_id, trigger_user_id: user.id, + container_id: package.id, container_type: 'ProjectPackage', tiding_type: 'Bidding') + end +end \ No newline at end of file diff --git a/app/services/project_packages/end_bidding_service.rb b/app/services/project_packages/end_bidding_service.rb new file mode 100644 index 00000000..86be02c7 --- /dev/null +++ b/app/services/project_packages/end_bidding_service.rb @@ -0,0 +1,26 @@ +class ProjectPackages::EndBiddingService + attr_reader :package + + def initialize(package) + @package = package + end + + def call + return unless package_deadline? + + package.end_bidding! + + send_bidding_end_notify! + end + + private + + def send_bidding_end_notify! + Tiding.create!(user_id: package.creator_id, trigger_user_id: 1, + container_id: package.id, container_type: 'ProjectPackage', tiding_type: 'BiddingEnd') + end + + def package_deadline? + package.deadline_at < Time.now + end +end \ No newline at end of file diff --git a/app/services/project_packages/refuse_apply_service.rb b/app/services/project_packages/refuse_apply_service.rb new file mode 100644 index 00000000..ee4c5bb7 --- /dev/null +++ b/app/services/project_packages/refuse_apply_service.rb @@ -0,0 +1,38 @@ +class ProjectPackages::RefuseApplyService + Error = Class.new(StandardError) + + attr_reader :apply, :package, :params + + def initialize(apply, params) + @apply = apply + @package = apply.project_package + @params = params + end + + def call + raise Error, '该状态下不能进行此操作' unless apply.may_refuse? && package.may_refuse? + + ActiveRecord::Base.transaction do + apply.refuse + apply.reason = params[:reason].to_s.strip + apply.save! + + # 发布 + package.refuse! + + # 消息 + send_refuse_notify! + end + end + + private + + def send_refuse_notify! + Tiding.where(container_id: package.id, container_type: 'ProjectPackage', + tiding_type: 'Apply', status: 0).update_all(status: 1) + + Tiding.create!(user_id: package.creator_id, trigger_user_id: 1, + container_id: package.id, container_type: 'ProjectPackage', + tiding_type: 'System', status: 2, extra: apply.reason) + end +end diff --git a/app/services/project_packages/save_service.rb b/app/services/project_packages/save_service.rb new file mode 100644 index 00000000..550ef346 --- /dev/null +++ b/app/services/project_packages/save_service.rb @@ -0,0 +1,66 @@ +class ProjectPackages::SaveService + Error = Class.new(StandardError) + + attr_reader :package, :params + + def initialize(package, params) + @package = package + @params = params + end + + def call + check_code_valid! if need_check_code? + + is_create = package.new_record? + + ActiveRecord::Base.transaction do + package.assign_attributes(params) + package.save! + + # 处理附件 + deal_attachments + + send_create_notify! if is_create + + ProjectPackages::ApplyPublishService.call(package) if with_publish? + end + + + package + rescue ProjectPackages::ApplyPublishService::Error => ex + raise Error, ex.message + end + + private + + def need_check_code? + (package.new_record? && params[:contact_phone] != package.creator.phone) || package.contact_phone != params[:contact_phone] + end + + def check_code_valid! + raise Error, '验证码不能为空' if params[:code].blank? + + code = VerificationCode.where(phone: params[:contact_phone], code_type: 9, code: params[:code]).last + raise Error, '无效的验证码' if code.blank? || !code.valid_code? + end + + def deal_attachments + attachment_ids = Array.wrap(params[:attachment_ids]).compact.map(&:to_i) || [] + old_attachment_ids = package.attachments.pluck(:id) + + destroy_ids = old_attachment_ids - attachment_ids + package.attachments.where(id: destroy_ids).delete_all + + new_ids = attachment_ids - old_attachment_ids + Attachment.where(id: new_ids).update_all(container_type: package.id, container_type: 'ProjectPackage') if new_ids.present? + end + + def send_create_notify! + Tiding.create!(user_id: package.creator_id, trigger_user_id: 1, + container_id: package.id, container_type: 'ProjectPackage', tiding_type: 'Created') + end + + def with_publish? + params[:publish].to_s == 'true' + end +end \ No newline at end of file diff --git a/app/services/project_packages/win_bidding_service.rb b/app/services/project_packages/win_bidding_service.rb new file mode 100644 index 00000000..f3efdcb7 --- /dev/null +++ b/app/services/project_packages/win_bidding_service.rb @@ -0,0 +1,47 @@ +class ProjectPackages::WinBiddingService + Error = Class.new(StandardError) + + attr_reader :package, :params + + def initialize(package, params) + @package = package + @params = params + end + + def call + raise Error, '竞标报名还未结束' unless package.bidding_end? + raise Error, '该状态下不能选择中标者' unless package.can_finish_bidding? + + win_user_ids = Array.wrap(params[:user_ids]).compact.map(&:to_i) + bidding_user_ids = package.bidding_users.pluck(:user_id) + + win_user_ids = bidding_user_ids & win_user_ids + raise Error, '请选择中标者' if win_user_ids.blank? + + ActiveRecord::Base.transaction do + package.finish_bidding! + + # win bidding users + package.bidding_users.where(user_id: win_user_ids).update_all(status: :bidding_won) + # lose bidding users + lost_user_ids = bidding_user_ids - win_user_ids + package.bidding_users.where(user_id: lost_user_ids).update_all(status: :bidding_lost) + + send_bidding_result_notify!('BiddingWon', win_user_ids) + send_bidding_result_notify!('BiddingLost', lost_user_ids) + end + + package + end + + private + + def send_bidding_result_notify!(type, user_ids) + sql = 'insert into tidings(user_id, trigger_user_id, container_id, container_type, tiding_type) values' + base_opts = [package.creator_id, package.id, 'ProjectPackage', type] + + values = '(' + user_ids.map { |id| base_opts.clone.unshift(id).join(',') }.join('),(') + ')' + + sql + values + end +end \ No newline at end of file diff --git a/app/views/layouts/base_management.html.erb b/app/views/layouts/base_management.html.erb index d17a05de..c59f80a8 100644 --- a/app/views/layouts/base_management.html.erb +++ b/app/views/layouts/base_management.html.erb @@ -117,6 +117,7 @@
  • <%= link_to '实训发布', shixun_authorization_managements_path %>
  • <%= link_to '实践课程发布', subject_authorization_managements_path %>
  • <%= link_to '教学案例发布', library_applies_path(status: :pending) %>
  • +
  • <%= link_to '众包需求发布', project_package_applies_path(status: :pending) %>
  • 认证+ diff --git a/app/views/managements/project_package_applies/_project_package_apply_list.html.erb b/app/views/managements/project_package_applies/_project_package_apply_list.html.erb new file mode 100644 index 00000000..baa5944d --- /dev/null +++ b/app/views/managements/project_package_applies/_project_package_apply_list.html.erb @@ -0,0 +1,76 @@ +<% if @applies.present? %> + <% @applies.each do |apply| %> + <% user = apply.project_package.user %> + <% project_package = apply.project_package %> +
    + + <%= image_tag(url_to_avatar(user), :class => "fl with10 edu-ad-user", :alt => "头像", :width => "50", :height => "50" ) %> + +
    + +
    +
    + <% end %> +
    +
    +
      + <%= pagination_links_full @obj_pages, @obj_count, :per_page_links => false, :remote => true, :flag => true, :is_new => true %> +
    +
    +
    +
    +<% else %> + <%= render :partial => "welcome/no_data" %> +<% end %> + + \ No newline at end of file diff --git a/app/views/managements/project_package_applies/index.html.erb b/app/views/managements/project_package_applies/index.html.erb new file mode 100644 index 00000000..4fbf7f60 --- /dev/null +++ b/app/views/managements/project_package_applies/index.html.erb @@ -0,0 +1,120 @@ +
    +
    +

    众包需求发布

    +
    +
    +
    +
      +
    • + <%= link_to "待审批", project_package_applies_path(status: :pending), class: 'tab_type', remote: true %> +
    • +
    • + <%= link_to "已审批", project_package_applies_path(status: [:refused, :agreed]), class: 'tab_type', remote: true %> +
    • +
    +
    +
    +
    +
    + + +
    +
    +
    + <%= render :partial => "managements/project_package_applies/project_package_apply_list"%> +
    +
    +
    + +
    +
    +

    + <%= link_to "全部", project_package_applies_path(status: [:refused, :agreed]), :class => "edu-filter-cir-grey mr5 fl font-12 active", :id => "project_package_all_authentication", :remote => true %> + <%= link_to "同意", project_package_applies_path(status: :agreed), :class => "edu-filter-cir-grey mr5 fl font-12", :id => "project_package_agree_authentication", :remote => true %> + <%= link_to "拒绝", project_package_applies_path(status: :refused), :class => "edu-filter-cir-grey mr5 fl font-12", :id => "project_package_reject_authentication", :remote => true %> +

    +
    + + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + \ No newline at end of file diff --git a/app/views/managements/project_package_applies/index.js.erb b/app/views/managements/project_package_applies/index.js.erb new file mode 100644 index 00000000..4e6d737d --- /dev/null +++ b/app/views/managements/project_package_applies/index.js.erb @@ -0,0 +1,30 @@ +var nTabIcon_1 = $("#edu-tab-con-1"); +var nTabIcon_2 = $("#edu-tab-con-2"); +var nTabNav_1 = $("#edu-tab-nav-1"); +var nTabNav_2 = $("#edu-tab-nav-2"); +var nAudit = $("#project_package_all_authentication").parent(); + +<% if params[:status].to_s == 'pending' %> +$("#authentication_list").html("<%= j( render :partial => "managements/project_package_applies/project_package_apply_list" ) %>"); +nTabNav_1.addClass("background-orange"); +nTabNav_2.removeClass("background-orange"); +nTabIcon_1.show(); +nTabIcon_2.hide(); +<% else %> +$("#project_package_authentication_list").html("<%= j( render :partial => "managements/project_package_applies/project_package_apply_list" ) %>"); +nTabNav_1.removeClass("background-orange"); +nTabNav_2.addClass("background-orange"); +nTabIcon_1.hide(); +nTabIcon_2.show(); +/* -------------------------- 未审批(全部、同意、拒绝点击时动态样式) ------------------------------ */ +if(<%= params[:status].to_s == 'agreed' %>){ + nAudit.find(".active").removeClass("active"); + $("#project_package_agree_authentication").addClass("active"); +}else if(<%= params[:status].to_s == 'refused' %>){ + nAudit.find(".active").removeClass("active"); + $("#project_package_reject_authentication").addClass("active"); +}else{ + nAudit.find(".active").removeClass("active"); + $("#project_package_all_authentication").addClass("active"); +} +<% end %> \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index c9d01c3b..bfdabd5c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -744,6 +744,13 @@ RedmineApp::Application.routes.draw do ## oauth相关 post :refuse end end + + resources :project_package_applies, only: [:index] do + member do + post :agree + post :refuse + end + end end end end diff --git a/db/migrate/20190709004039_create_project_packages.rb b/db/migrate/20190709004039_create_project_packages.rb new file mode 100644 index 00000000..0ded2fdb --- /dev/null +++ b/db/migrate/20190709004039_create_project_packages.rb @@ -0,0 +1,28 @@ +class CreateProjectPackages < ActiveRecord::Migration + def change + create_table :project_packages do |t| + t.references :creator + t.string :category + t.string :status + + t.string :title + t.text :content + t.string :contact_name + t.string :contact_phone + + t.decimal :min_price + t.decimal :max_price + + t.integer :visit_count, default: 0 + t.integer :bidding_users_count, default: 0 + + t.datetime :deadline_at + t.datetime :published_at + t.datetime :bidding_finished_at + + t.timestamps + end + + add_index :project_packages, :published_at + end +end diff --git a/db/migrate/20190709010031_create_bidding_users.rb b/db/migrate/20190709010031_create_bidding_users.rb new file mode 100644 index 00000000..597d658c --- /dev/null +++ b/db/migrate/20190709010031_create_bidding_users.rb @@ -0,0 +1,12 @@ +class CreateBiddingUsers < ActiveRecord::Migration + def change + create_table :bidding_users do |t| + t.references :project_package + t.references :user + + t.string :status + + t.timestamps + end + end +end diff --git a/db/migrate/20190709023928_create_project_package_applies.rb b/db/migrate/20190709023928_create_project_package_applies.rb new file mode 100644 index 00000000..6bdff178 --- /dev/null +++ b/db/migrate/20190709023928_create_project_package_applies.rb @@ -0,0 +1,14 @@ +class CreateProjectPackageApplies < ActiveRecord::Migration + def change + create_table :project_package_applies do |t| + t.references :project_package + + t.string :status + t.string :reason + + t.datetime :refused_at + + t.timestamps + end + end +end From 3f55927a7e1fba418a0d378b991e85aeb4cb743f Mon Sep 17 00:00:00 2001 From: p31729568 Date: Wed, 10 Jul 2019 09:54:16 +0800 Subject: [PATCH 02/42] fix encode --- app/api/mobile/apis/project_packages.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/api/mobile/apis/project_packages.rb b/app/api/mobile/apis/project_packages.rb index d5c4143f..1fa7715d 100644 --- a/app/api/mobile/apis/project_packages.rb +++ b/app/api/mobile/apis/project_packages.rb @@ -1,3 +1,5 @@ +# encoding=utf-8 + module Mobile module Apis class ProjectPackages < Grape::API From 5d03a2d61764539f7769b3a330c99e4a1dc8ff0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com> Date: Wed, 10 Jul 2019 10:19:46 +0800 Subject: [PATCH 03/42] =?UTF-8?q?=E8=BF=81=E7=A7=BB=E5=AD=97=E7=AC=A6?= =?UTF-8?q?=E9=9B=86=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../20190701022644_transfer_competition_personal_enroll_data.rb | 1 + db/migrate/20190705071020_create_library_tags.rb | 1 + 2 files changed, 2 insertions(+) diff --git a/db/migrate/20190701022644_transfer_competition_personal_enroll_data.rb b/db/migrate/20190701022644_transfer_competition_personal_enroll_data.rb index 4c59ad14..7122470c 100644 --- a/db/migrate/20190701022644_transfer_competition_personal_enroll_data.rb +++ b/db/migrate/20190701022644_transfer_competition_personal_enroll_data.rb @@ -1,3 +1,4 @@ +# encoding=utf-8 class TransferCompetitionPersonalEnrollData < ActiveRecord::Migration CODES = %W(2 3 4 5 6 7 8 9 a b c f e f g h i j k l m n o p q r s t u v w x y z) diff --git a/db/migrate/20190705071020_create_library_tags.rb b/db/migrate/20190705071020_create_library_tags.rb index 62b94c01..b3e458eb 100644 --- a/db/migrate/20190705071020_create_library_tags.rb +++ b/db/migrate/20190705071020_create_library_tags.rb @@ -1,3 +1,4 @@ +# encoding=utf-8 class CreateLibraryTags < ActiveRecord::Migration def change create_table :library_tags do |t| From 17231d64b820888d63e5ba00e01218c4706263f6 Mon Sep 17 00:00:00 2001 From: p31729568 Date: Wed, 10 Jul 2019 10:26:31 +0800 Subject: [PATCH 04/42] add project package routes --- .../project_packages_controller.rb | 29 +++++++++++++++++++ config/routes.rb | 2 ++ 2 files changed, 31 insertions(+) create mode 100644 app/controllers/project_packages_controller.rb diff --git a/app/controllers/project_packages_controller.rb b/app/controllers/project_packages_controller.rb new file mode 100644 index 00000000..cdedea9e --- /dev/null +++ b/app/controllers/project_packages_controller.rb @@ -0,0 +1,29 @@ +# encoding=utf-8 +# For react +class ProjectPackagesController < ApplicationController + before_filter :require_login, :except => [:index] + + include ApplicationHelper + + def show + render_react + end + + def new + render_react + end + + def index + render_react + end + + def edit + render_react + end + + private + def render_react + render file: 'public/react/build/index.html', :layout => false + end + +end diff --git a/config/routes.rb b/config/routes.rb index bfdabd5c..762096f0 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -57,6 +57,8 @@ RedmineApp::Application.routes.draw do ## oauth相关 get :publish_success, on: :collection end + resources :project_packages, only: [:index, :show, :new, :edit] + resources :ec_course_evaluations do member do match 'import_score', :via => [:post] From 05bd1ca0c82eb124373e097acf291a0bbe18cc50 Mon Sep 17 00:00:00 2001 From: p31729568 Date: Wed, 10 Jul 2019 14:25:52 +0800 Subject: [PATCH 05/42] user center project package list --- .../project_packages_controller.rb | 4 + app/controllers/users_controller.rb | 50 ++++++++++ app/models/bidding_user.rb | 4 + app/models/user.rb | 2 + app/views/users/_project_package.html.erb | 82 ++++++++++++++++ app/views/users/show.html.erb | 16 +++ app/views/users/show.js.erb | 4 + config/locales/bidding_users/zh.yml | 6 ++ config/routes.rb | 4 +- .../images/educoder/project_packages/ai.png | Bin 0 -> 1459 bytes .../educoder/project_packages/backend.png | Bin 0 -> 1404 bytes .../cloud_compute_and_big_data.png | Bin 0 -> 1506 bytes .../educoder/project_packages/database.png | Bin 0 -> 1627 bytes .../project_packages/devops_and_test.png | Bin 0 -> 1312 bytes .../educoder/project_packages/front.png | Bin 0 -> 1322 bytes .../educoder/project_packages/mobile.png | Bin 0 -> 1367 bytes .../educoder/project_packages/other.png | Bin 0 -> 1107 bytes public/stylesheets/educoder/edu-main.css | 91 ++++++++++++++++++ 18 files changed, 262 insertions(+), 1 deletion(-) create mode 100644 app/views/users/_project_package.html.erb create mode 100644 config/locales/bidding_users/zh.yml create mode 100755 public/images/educoder/project_packages/ai.png create mode 100755 public/images/educoder/project_packages/backend.png create mode 100755 public/images/educoder/project_packages/cloud_compute_and_big_data.png create mode 100755 public/images/educoder/project_packages/database.png create mode 100755 public/images/educoder/project_packages/devops_and_test.png create mode 100755 public/images/educoder/project_packages/front.png create mode 100755 public/images/educoder/project_packages/mobile.png create mode 100755 public/images/educoder/project_packages/other.png diff --git a/app/controllers/project_packages_controller.rb b/app/controllers/project_packages_controller.rb index cdedea9e..3945f978 100644 --- a/app/controllers/project_packages_controller.rb +++ b/app/controllers/project_packages_controller.rb @@ -21,6 +21,10 @@ class ProjectPackagesController < ApplicationController render_react end + def apply_success + render_react + end + private def render_react render file: 'public/react/build/index.html', :layout => false diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 4fae7ff7..3306326e 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -2558,6 +2558,56 @@ class UsersController < ApplicationController @tag = params[:tag] @objects = @objects.where(:course_list_id => params[:tag]).order("#{@sort} #{order}") end + when 'a_package' + bidding_packages = @user.bidding_project_packages + bidding_packages = bidding_packages.none if @show_all && params[:q] == 0 # 参与的不存在未发布的 + packages = @user.project_packages + + if @show_all + status = + case params[:q] + when '0' then %w(pending applying refused) + when '1' then %w(published) + when '2' then %w(bidding_ended bidding_finished) + end + if status.present? + packages = packages.where(status: status) + bidding_packages = bidding_packages.where(status: status) + end + else + packages = packages.where(status: %w(published bidding_ended bidding_finished)) + end + + ids = bidding_packages.pluck(:id) + packages.pluck(:id) + @objects = ProjectPackage.where(id: ids).order("published_at #{order}") + when 'p_package' + packages = @user.project_packages + if @show_all + status = + case params[:q] + when '0' then %w(pending applying refused) + when '1' then %w(published) + when '2' then %w(bidding_ended bidding_finished) + end + if status.present? + packages = packages.where(status: status) + end + else + packages = packages.where(status: %w(published bidding_ended bidding_finished)) + end + @objects = packages.order("published_at #{order}") + when 'l_package' + packages = @user.bidding_project_packages + if @show_all + status = + case params[:q] + when '0' then %w(bidding_lost) + when '1' then %w(bidding_won) + end + + packages = packages.where(bidding_users: { status: status }) if status.present? + end + @objects = packages.order("published_at #{order}") end @objects_count = @objects.size diff --git a/app/models/bidding_user.rb b/app/models/bidding_user.rb index 5869b6d4..9f368b2a 100644 --- a/app/models/bidding_user.rb +++ b/app/models/bidding_user.rb @@ -17,4 +17,8 @@ class BiddingUser < ActiveRecord::Base transitions from: [:pending], to: :bid_lost end end + + def status_text + I18n.t("bidding_user.status.#{status}") + end end \ No newline at end of file diff --git a/app/models/user.rb b/app/models/user.rb index b5545206..0e034d32 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -276,6 +276,8 @@ class User < Principal # 众包 has_many :project_packages, foreign_key: :creator_id, dependent: :destroy + has_many :bidding_users, dependent: :destroy + has_many :bidding_project_packages, through: :bidding_users, source: :project_package ## end diff --git a/app/views/users/_project_package.html.erb b/app/views/users/_project_package.html.erb new file mode 100644 index 00000000..d8ca475e --- /dev/null +++ b/app/views/users/_project_package.html.erb @@ -0,0 +1,82 @@ +<% if @type == 'p_package' && User.current == @user %> +
    +
  • <%= link_to "全部", user_path(@user, :type => @type), :remote => true %>
  • +
  • <%= link_to "未发布", user_path(@user, :type => @type, :p => "0"), :remote => true %>
  • +
  • <%= link_to "竞标中", user_path(@user, :type => @type, :p => "1"), :remote => true %>
  • +
  • <%= link_to "已完成", user_path(@user, :type => @type, :p => "2"), :remote => true %>
  • + +<% elsif @type == 'l_package' && User.current == @user %> +
    +
  • <%= link_to "全部", user_path(@user, :type => @type, :p => "a"), :remote => true %>
  • +
  • <%= link_to "未中标", user_path(@user, :type => @type, :p => "0"), :remote => true %>
  • +
  • <%= link_to "已中标", user_path(@user, :type => @type, :p => "1"), :remote => true %>
  • +
    +<% end %> + +
    + 共<%= @objects_count %>个 +
    + <%= link_to '发布时间', user_path(@user, :order => @new_order, :sort => @sort, :type => @type), :class => "fl color-grey-9", :remote => true %> +
    +
    + +<% if @objects_count > 0 %> +
    + <% @objects.each do |object| %> +
    +
    + <%= image_tag("educoder/project_packages/#{object.category}.png") %> +
    +
    +
    +
    + <%= link_to object.title, project_package_path(object) %> +
    +
    + <% if object.creator_id != @user.id %> + <% bidding_user = object.bidding_users.find_by_user_id(@user.id) %> + <%= raw content_tag(:span, bidding_user.status_text, class: bidding_user.status) %> + <% end %> +
    +
    +
    + <%= object.min_price %> + <% if object.max_price && object.max_price != object.min_price %> + ~<%= object.max_price %> + <% end %> +
    +
    +
    +
    人工智能
    +
    +
    +
    + + <%= object.visit_count %>人浏览 +
    +
    + <% if object.published? %> + + 内竞标截止 + <% end %> +
    +
    + <% if object.bidding_users_count > 0 %> + + <%= object.bidding_users_count %>人竞标 + <% end %> +
    +
    +
    + <% if object.published_at.present? %> + 发布日期:<%= object.published_at.try(:strftime, '%Y-%m-%d') %> + <% end %> +
    +
    +
    +
    + <% end %> +
    +<% else %> + <%= render :partial => "welcome/no_data" %> +<% end %> \ No newline at end of file diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb index 6d42f201..fb459160 100644 --- a/app/views/users/show.html.erb +++ b/app/views/users/show.html.erb @@ -1,6 +1,8 @@ <% current_user = @user == User.current %> <% str = current_user ? '我' : 'TA' %> +<% show_package = @user.project_packages.count.nonzero? || @user.bidding_project_packages.count.nonzero? %> + \ No newline at end of file diff --git a/config/locales/project_packages/zh.yml b/config/locales/project_packages/zh.yml new file mode 100644 index 00000000..40915dfe --- /dev/null +++ b/config/locales/project_packages/zh.yml @@ -0,0 +1,11 @@ +zh: + project_package: + category: + front: 前端开发 + backend: 后端开发 + mobile: 移动开发 + database: 数据库 + cloud_compute_and_big_data: 云计算与大数据 + devops_and_test: 运维与测试 + ai: 人工智能 + other: 其它 \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index d0108fe1..78c35a76 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -57,7 +57,7 @@ RedmineApp::Application.routes.draw do ## oauth相关 get :publish_success, on: :collection end - resources :project_packages, only: [:index, :show, :new, :edit] do + resources :project_packages, only: [:index, :show, :new, :edit, :destroy] do get :apply_success, on: :member end diff --git a/public/stylesheets/educoder/edu-main.css b/public/stylesheets/educoder/edu-main.css index 3debdf6f..233f5682 100644 --- a/public/stylesheets/educoder/edu-main.css +++ b/public/stylesheets/educoder/edu-main.css @@ -980,7 +980,6 @@ html>body #ajax-indicator { position: fixed; } margin-bottom: 20px; padding: 20px; background: white; - box-shadow:1px 3px 3px 1px rgba(156,156,156,0.16); } .project-packages-list .project-package-item:hover{ @@ -1018,12 +1017,22 @@ html>body #ajax-indicator { position: fixed; } overflow: hidden; text-overflow: ellipsis; } +.project-package-item .item-head-tags { + display: -webkit-flex; + display: flex; + align-items: center; +} .project-package-item .item-head-tags span { + margin-left: 20px; + padding: 0 10px; + height: 28px; + font-size: 14px; color: white; + border-radius: 5px; } -.project-package-item .item-head-tags span.pending { color: red; } -.project-package-item .item-head-tags span.bidding_won { color: lightgreen; } -.project-package-item .item-head-tags span.bidding_lost { color: grey; } +.project-package-item .item-head-tags span.pending { background: lightcoral; } +.project-package-item .item-head-tags span.bidding_won { background: lightgreen; } +.project-package-item .item-head-tags span.bidding_lost { background: grey; } .project-package-item .item-head-blank { flex: 1; @@ -1055,8 +1064,36 @@ html>body #ajax-indicator { position: fixed; } color: #999999; } .project-package-item .item-group { - flex: 1; + flex: 2; } .project-package-item .item-other-blank { - flex: 2 + flex: 3 +} + +.project-package-item.with-operator .item-operator { + width: 0; +} +.project-package-item.with-operator:hover .item-operator { + margin: -20px -20px -20px 20px; + padding: 20px 0; + width: 100px; + display: flex; + justify-content: space-around; + flex-direction: column; + align-items: center; + background: #f0f0f0; + transition: width .2s; + -moz-transition: width .2s; /* Firefox 4 */ + -webkit-transition: width .2s; /* Safari 和 Chrome */ + -o-transition: width .2s; /* Opera */ +} +.project-package-item.with-operator .item-operator a { + display: none; +} +.project-package-item.with-operator:hover .item-operator a { + display: block; + font-size: 20px; +} +.project-package-item.with-operator:hover .item-head-title { + max-width: 600px; } \ No newline at end of file From 9fd471e6b17d5489ceb53792322ce86cf9fee5ed Mon Sep 17 00:00:00 2001 From: p31729568 Date: Wed, 10 Jul 2019 17:08:34 +0800 Subject: [PATCH 07/42] modify style --- public/stylesheets/educoder/edu-main.css | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/public/stylesheets/educoder/edu-main.css b/public/stylesheets/educoder/edu-main.css index 233f5682..79385ef4 100644 --- a/public/stylesheets/educoder/edu-main.css +++ b/public/stylesheets/educoder/edu-main.css @@ -1057,6 +1057,7 @@ html>body #ajax-indicator { position: fixed; } background:rgba(255,235,213,1); border-radius:13px; } + .project-package-item .item-other { display: -webkit-flex; display: flex; @@ -1066,12 +1067,19 @@ html>body #ajax-indicator { position: fixed; } .project-package-item .item-group { flex: 2; } +.project-package-item .item-group.item-other-publish-at { + text-align: right; +} .project-package-item .item-other-blank { flex: 3 } .project-package-item.with-operator .item-operator { width: 0; + transition: width .2s; + -moz-transition: width .2s; /* Firefox 4 */ + -webkit-transition: width .2s; /* Safari 和 Chrome */ + -o-transition: width .2s; /* Opera */ } .project-package-item.with-operator:hover .item-operator { margin: -20px -20px -20px 20px; @@ -1082,10 +1090,6 @@ html>body #ajax-indicator { position: fixed; } flex-direction: column; align-items: center; background: #f0f0f0; - transition: width .2s; - -moz-transition: width .2s; /* Firefox 4 */ - -webkit-transition: width .2s; /* Safari 和 Chrome */ - -o-transition: width .2s; /* Opera */ } .project-package-item.with-operator .item-operator a { display: none; From da8ed2187ae5d29e092d4a6ed5848c1b79caa16f Mon Sep 17 00:00:00 2001 From: p31729568 Date: Wed, 10 Jul 2019 17:13:20 +0800 Subject: [PATCH 08/42] modify css --- public/stylesheets/educoder/edu-main.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/public/stylesheets/educoder/edu-main.css b/public/stylesheets/educoder/edu-main.css index 79385ef4..5a4d2c48 100644 --- a/public/stylesheets/educoder/edu-main.css +++ b/public/stylesheets/educoder/edu-main.css @@ -1016,6 +1016,10 @@ html>body #ajax-indicator { position: fixed; } white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + transition: max-width .2s; + -moz-transition: max-width .2s; /* Firefox 4 */ + -webkit-transition: max-width .2s; /* Safari 和 Chrome */ + -o-transition: max-width .2s; /* Opera */ } .project-package-item .item-head-tags { display: -webkit-flex; From 737e992d044bec0c41180f9cdb37d21d7c06c107 Mon Sep 17 00:00:00 2001 From: p31729568 Date: Wed, 10 Jul 2019 17:20:06 +0800 Subject: [PATCH 09/42] add sort direction support --- app/api/mobile/apis/project_packages.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/api/mobile/apis/project_packages.rb b/app/api/mobile/apis/project_packages.rb index 01af989b..591e54b1 100644 --- a/app/api/mobile/apis/project_packages.rb +++ b/app/api/mobile/apis/project_packages.rb @@ -21,6 +21,7 @@ module Mobile optional :category, type: String, desc: '类型' optional :keyword, type: String, desc: '搜索关键字' optional :sort_by, type: String, desc: '排序' + optional :sort_direction, type: String, desc: '排序方向' optional :page, type: Integer, desc: '页数' optional :per_page, type: Integer, desc: '分页大小' end @@ -34,11 +35,10 @@ module Mobile count = packages.count - if params[:sort_by] == 'price' - packages = packages.order('min_price desc') - else - packages = packages.order('published_at desc') - end + direction = params[:sort_direction] == 'asc' ? 'asc' : 'desc' + sort = params[:sort_by] == 'price' ? 'min_price' : 'published_at' + packages = packages.order("#{sort} #{direction}") + packages = paginate packages.includes(:creator, :attachments, bidding_users: :user) present :count, count From e0cdef3ce92c186d2b535318113f91400994772e Mon Sep 17 00:00:00 2001 From: p31729568 Date: Wed, 10 Jul 2019 17:21:53 +0800 Subject: [PATCH 10/42] fix project package save service --- app/services/project_packages/save_service.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/services/project_packages/save_service.rb b/app/services/project_packages/save_service.rb index 42fda69b..9011722c 100644 --- a/app/services/project_packages/save_service.rb +++ b/app/services/project_packages/save_service.rb @@ -51,7 +51,9 @@ class ProjectPackages::SaveService package.attachments.where(id: destroy_ids).delete_all new_ids = attachment_ids - old_attachment_ids - Attachment.where(id: new_ids).update_all(container_type: package.id, container_type: 'ProjectPackage') if new_ids.present? + if new_ids.present? + Attachment.where(id: new_ids, container_id: nil).update_all(container_id: package.id, container_type: 'ProjectPackage') + end end def send_create_notify! From 84a99dc3f57f363cf6f6a3d8654cb2567a839e25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com> Date: Wed, 10 Jul 2019 18:13:23 +0800 Subject: [PATCH 11/42] =?UTF-8?q?=E4=BC=97=E5=8C=85=E9=A6=96=E9=A1=B5?= =?UTF-8?q?=E5=92=8C=E6=96=B0=E5=BB=BA=E7=BC=96=E8=BE=91=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Gemfile | 4 +- public/editormd/scss/font-awesome.scss | 1813 +------------ public/react/public/css/font-awesome.css | 2338 ++++++++++++++++- public/react/src/App.js | 6 + public/react/src/index.js | 6 +- .../PackageIndex/PackageBanner.js | 25 + .../PackageIndex/PackageConcent.js | 154 ++ .../PackageIndex/PackageIndex.js | 30 + .../PackageIndexNEIBanner.js | 42 + .../PackageIndexNEIBannerConcent.js | 66 + .../PackageIndexNewandEditIndex.js | 39 + .../projectPackages/ProjectPackageIndex.js | 45 + .../projectPackages/packageconcnet.css | 71 + public/react/src/modules/tpm/NewHeader.js | 19 +- public/stylesheets/educoder/edu-main.css | 4 +- 15 files changed, 2849 insertions(+), 1813 deletions(-) create mode 100644 public/react/src/modules/projectPackages/PackageIndex/PackageBanner.js create mode 100644 public/react/src/modules/projectPackages/PackageIndex/PackageConcent.js create mode 100644 public/react/src/modules/projectPackages/PackageIndex/PackageIndex.js create mode 100644 public/react/src/modules/projectPackages/PackageIndexNewandEdit/PackageIndexNEIBanner.js create mode 100644 public/react/src/modules/projectPackages/PackageIndexNewandEdit/PackageIndexNEIBannerConcent.js create mode 100644 public/react/src/modules/projectPackages/PackageIndexNewandEdit/PackageIndexNewandEditIndex.js create mode 100644 public/react/src/modules/projectPackages/ProjectPackageIndex.js create mode 100644 public/react/src/modules/projectPackages/packageconcnet.css diff --git a/Gemfile b/Gemfile index d89f9a24..ac45f360 100644 --- a/Gemfile +++ b/Gemfile @@ -64,8 +64,8 @@ gem 'elasticsearch-rails' gem 'oauth2' # xlsx -gem 'axlsx', '3.0.0.pre' -gem 'axlsx_rails', '0.3.0' +# gem 'axlsx', '3.0.0.pre' +# gem 'axlsx_rails', '0.3.0' # state machine gem 'aasm' diff --git a/public/editormd/scss/font-awesome.scss b/public/editormd/scss/font-awesome.scss index 2dcdc220..f1c83aaa 100644 --- a/public/editormd/scss/font-awesome.scss +++ b/public/editormd/scss/font-awesome.scss @@ -1,1801 +1,18 @@ /*! - * Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) */ -/* FONT PATH - * -------------------------- */ -@font-face { - font-family: 'FontAwesome'; - src: url('../fonts/fontawesome-webfont.eot?v=4.3.0'); - src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.3.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff2?v=4.3.0') format('woff2'), url('../fonts/fontawesome-webfont.woff?v=4.3.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.3.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.3.0#fontawesomeregular') format('svg'); - font-weight: normal; - font-style: normal; -} -.fa { - display: inline-block; - font: normal normal normal 14px/1 FontAwesome; - font-size: inherit; - text-rendering: auto; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - transform: translate(0, 0); -} -/* makes the font 33% larger relative to the icon container */ -.fa-lg { - font-size: 1.33333333em; - line-height: 0.75em; - vertical-align: -15%; -} -.fa-2x { - font-size: 2em; -} -.fa-3x { - font-size: 3em; -} -.fa-4x { - font-size: 4em; -} -.fa-5x { - font-size: 5em; -} -.fa-fw { - width: 1.28571429em; - text-align: center; -} -.fa-ul { - padding-left: 0; - margin-left: 2.14285714em; - list-style-type: none; -} -.fa-ul > li { - position: relative; -} -.fa-li { - position: absolute; - left: -2.14285714em; - width: 2.14285714em; - top: 0.14285714em; - text-align: center; -} -.fa-li.fa-lg { - left: -1.85714286em; -} -.fa-border { - padding: .2em .25em .15em; - border: solid 0.08em #eeeeee; - border-radius: .1em; -} -.pull-right { - float: right; -} -.pull-left { - float: left; -} -.fa.pull-left { - margin-right: .3em; -} -.fa.pull-right { - margin-left: .3em; -} -.fa-spin { - -webkit-animation: fa-spin 2s infinite linear; - animation: fa-spin 2s infinite linear; -} -.fa-pulse { - -webkit-animation: fa-spin 1s infinite steps(8); - animation: fa-spin 1s infinite steps(8); -} -@-webkit-keyframes fa-spin { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(359deg); - transform: rotate(359deg); - } -} -@keyframes fa-spin { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(359deg); - transform: rotate(359deg); - } -} -.fa-rotate-90 { - filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1); - -webkit-transform: rotate(90deg); - -ms-transform: rotate(90deg); - transform: rotate(90deg); -} -.fa-rotate-180 { - filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2); - -webkit-transform: rotate(180deg); - -ms-transform: rotate(180deg); - transform: rotate(180deg); -} -.fa-rotate-270 { - filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3); - -webkit-transform: rotate(270deg); - -ms-transform: rotate(270deg); - transform: rotate(270deg); -} -.fa-flip-horizontal { - filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1); - -webkit-transform: scale(-1, 1); - -ms-transform: scale(-1, 1); - transform: scale(-1, 1); -} -.fa-flip-vertical { - filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1); - -webkit-transform: scale(1, -1); - -ms-transform: scale(1, -1); - transform: scale(1, -1); -} -:root .fa-rotate-90, -:root .fa-rotate-180, -:root .fa-rotate-270, -:root .fa-flip-horizontal, -:root .fa-flip-vertical { - filter: none; -} -.fa-stack { - position: relative; - display: inline-block; - width: 2em; - height: 2em; - line-height: 2em; - vertical-align: middle; -} -.fa-stack-1x, -.fa-stack-2x { - position: absolute; - left: 0; - width: 100%; - text-align: center; -} -.fa-stack-1x { - line-height: inherit; -} -.fa-stack-2x { - font-size: 2em; -} -.fa-inverse { - color: #ffffff; -} -/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen - readers do not read off random characters that represent icons */ -.fa-glass:before { - content: "\f000"; -} -.fa-music:before { - content: "\f001"; -} -.fa-search:before { - content: "\f002"; -} -.fa-envelope-o:before { - content: "\f003"; -} -.fa-heart:before { - content: "\f004"; -} -.fa-star:before { - content: "\f005"; -} -.fa-star-o:before { - content: "\f006"; -} -.fa-user:before { - content: "\f007"; -} -.fa-film:before { - content: "\f008"; -} -.fa-th-large:before { - content: "\f009"; -} -.fa-th:before { - content: "\f00a"; -} -.fa-th-list:before { - content: "\f00b"; -} -.fa-check:before { - content: "\f00c"; -} -.fa-remove:before, -.fa-close:before, -.fa-times:before { - content: "\f00d"; -} -.fa-search-plus:before { - content: "\f00e"; -} -.fa-search-minus:before { - content: "\f010"; -} -.fa-power-off:before { - content: "\f011"; -} -.fa-signal:before { - content: "\f012"; -} -.fa-gear:before, -.fa-cog:before { - content: "\f013"; -} -.fa-trash-o:before { - content: "\f014"; -} -.fa-home:before { - content: "\f015"; -} -.fa-file-o:before { - content: "\f016"; -} -.fa-clock-o:before { - content: "\f017"; -} -.fa-road:before { - content: "\f018"; -} -.fa-download:before { - content: "\f019"; -} -.fa-arrow-circle-o-down:before { - content: "\f01a"; -} -.fa-arrow-circle-o-up:before { - content: "\f01b"; -} -.fa-inbox:before { - content: "\f01c"; -} -.fa-play-circle-o:before { - content: "\f01d"; -} -.fa-rotate-right:before, -.fa-repeat:before { - content: "\f01e"; -} -.fa-refresh:before { - content: "\f021"; -} -.fa-list-alt:before { - content: "\f022"; -} -.fa-lock:before { - content: "\f023"; -} -.fa-flag:before { - content: "\f024"; -} -.fa-headphones:before { - content: "\f025"; -} -.fa-volume-off:before { - content: "\f026"; -} -.fa-volume-down:before { - content: "\f027"; -} -.fa-volume-up:before { - content: "\f028"; -} -.fa-qrcode:before { - content: "\f029"; -} -.fa-barcode:before { - content: "\f02a"; -} -.fa-tag:before { - content: "\f02b"; -} -.fa-tags:before { - content: "\f02c"; -} -.fa-book:before { - content: "\f02d"; -} -.fa-bookmark:before { - content: "\f02e"; -} -.fa-print:before { - content: "\f02f"; -} -.fa-camera:before { - content: "\f030"; -} -.fa-font:before { - content: "\f031"; -} -.fa-bold:before { - content: "\f032"; -} -.fa-italic:before { - content: "\f033"; -} -.fa-text-height:before { - content: "\f034"; -} -.fa-text-width:before { - content: "\f035"; -} -.fa-align-left:before { - content: "\f036"; -} -.fa-align-center:before { - content: "\f037"; -} -.fa-align-right:before { - content: "\f038"; -} -.fa-align-justify:before { - content: "\f039"; -} -.fa-list:before { - content: "\f03a"; -} -.fa-dedent:before, -.fa-outdent:before { - content: "\f03b"; -} -.fa-indent:before { - content: "\f03c"; -} -.fa-video-camera:before { - content: "\f03d"; -} -.fa-photo:before, -.fa-image:before, -.fa-picture-o:before { - content: "\f03e"; -} -.fa-pencil:before { - content: "\f040"; -} -.fa-map-marker:before { - content: "\f041"; -} -.fa-adjust:before { - content: "\f042"; -} -.fa-tint:before { - content: "\f043"; -} -.fa-edit:before, -.fa-pencil-square-o:before { - content: "\f044"; -} -.fa-share-square-o:before { - content: "\f045"; -} -.fa-check-square-o:before { - content: "\f046"; -} -.fa-arrows:before { - content: "\f047"; -} -.fa-step-backward:before { - content: "\f048"; -} -.fa-fast-backward:before { - content: "\f049"; -} -.fa-backward:before { - content: "\f04a"; -} -.fa-play:before { - content: "\f04b"; -} -.fa-pause:before { - content: "\f04c"; -} -.fa-stop:before { - content: "\f04d"; -} -.fa-forward:before { - content: "\f04e"; -} -.fa-fast-forward:before { - content: "\f050"; -} -.fa-step-forward:before { - content: "\f051"; -} -.fa-eject:before { - content: "\f052"; -} -.fa-chevron-left:before { - content: "\f053"; -} -.fa-chevron-right:before { - content: "\f054"; -} -.fa-plus-circle:before { - content: "\f055"; -} -.fa-minus-circle:before { - content: "\f056"; -} -.fa-times-circle:before { - content: "\f057"; -} -.fa-check-circle:before { - content: "\f058"; -} -.fa-question-circle:before { - content: "\f059"; -} -.fa-info-circle:before { - content: "\f05a"; -} -.fa-crosshairs:before { - content: "\f05b"; -} -.fa-times-circle-o:before { - content: "\f05c"; -} -.fa-check-circle-o:before { - content: "\f05d"; -} -.fa-ban:before { - content: "\f05e"; -} -.fa-arrow-left:before { - content: "\f060"; -} -.fa-arrow-right:before { - content: "\f061"; -} -.fa-arrow-up:before { - content: "\f062"; -} -.fa-arrow-down:before { - content: "\f063"; -} -.fa-mail-forward:before, -.fa-share:before { - content: "\f064"; -} -.fa-expand:before { - content: "\f065"; -} -.fa-compress:before { - content: "\f066"; -} -.fa-plus:before { - content: "\f067"; -} -.fa-minus:before { - content: "\f068"; -} -.fa-asterisk:before { - content: "\f069"; -} -.fa-exclamation-circle:before { - content: "\f06a"; -} -.fa-gift:before { - content: "\f06b"; -} -.fa-leaf:before { - content: "\f06c"; -} -.fa-fire:before { - content: "\f06d"; -} -.fa-eye:before { - content: "\f06e"; -} -.fa-eye-slash:before { - content: "\f070"; -} -.fa-warning:before, -.fa-exclamation-triangle:before { - content: "\f071"; -} -.fa-plane:before { - content: "\f072"; -} -.fa-calendar:before { - content: "\f073"; -} -.fa-random:before { - content: "\f074"; -} -.fa-comment:before { - content: "\f075"; -} -.fa-magnet:before { - content: "\f076"; -} -.fa-chevron-up:before { - content: "\f077"; -} -.fa-chevron-down:before { - content: "\f078"; -} -.fa-retweet:before { - content: "\f079"; -} -.fa-shopping-cart:before { - content: "\f07a"; -} -.fa-folder:before { - content: "\f07b"; -} -.fa-folder-open:before { - content: "\f07c"; -} -.fa-arrows-v:before { - content: "\f07d"; -} -.fa-arrows-h:before { - content: "\f07e"; -} -.fa-bar-chart-o:before, -.fa-bar-chart:before { - content: "\f080"; -} -.fa-twitter-square:before { - content: "\f081"; -} -.fa-facebook-square:before { - content: "\f082"; -} -.fa-camera-retro:before { - content: "\f083"; -} -.fa-key:before { - content: "\f084"; -} -.fa-gears:before, -.fa-cogs:before { - content: "\f085"; -} -.fa-comments:before { - content: "\f086"; -} -.fa-thumbs-o-up:before { - content: "\f087"; -} -.fa-thumbs-o-down:before { - content: "\f088"; -} -.fa-star-half:before { - content: "\f089"; -} -.fa-heart-o:before { - content: "\f08a"; -} -.fa-sign-out:before { - content: "\f08b"; -} -.fa-linkedin-square:before { - content: "\f08c"; -} -.fa-thumb-tack:before { - content: "\f08d"; -} -.fa-external-link:before { - content: "\f08e"; -} -.fa-sign-in:before { - content: "\f090"; -} -.fa-trophy:before { - content: "\f091"; -} -.fa-github-square:before { - content: "\f092"; -} -.fa-upload:before { - content: "\f093"; -} -.fa-lemon-o:before { - content: "\f094"; -} -.fa-phone:before { - content: "\f095"; -} -.fa-square-o:before { - content: "\f096"; -} -.fa-bookmark-o:before { - content: "\f097"; -} -.fa-phone-square:before { - content: "\f098"; -} -.fa-twitter:before { - content: "\f099"; -} -.fa-facebook-f:before, -.fa-facebook:before { - content: "\f09a"; -} -.fa-github:before { - content: "\f09b"; -} -.fa-unlock:before { - content: "\f09c"; -} -.fa-credit-card:before { - content: "\f09d"; -} -.fa-rss:before { - content: "\f09e"; -} -.fa-hdd-o:before { - content: "\f0a0"; -} -.fa-bullhorn:before { - content: "\f0a1"; -} -.fa-bell:before { - content: "\f0f3"; -} -.fa-certificate:before { - content: "\f0a3"; -} -.fa-hand-o-right:before { - content: "\f0a4"; -} -.fa-hand-o-left:before { - content: "\f0a5"; -} -.fa-hand-o-up:before { - content: "\f0a6"; -} -.fa-hand-o-down:before { - content: "\f0a7"; -} -.fa-arrow-circle-left:before { - content: "\f0a8"; -} -.fa-arrow-circle-right:before { - content: "\f0a9"; -} -.fa-arrow-circle-up:before { - content: "\f0aa"; -} -.fa-arrow-circle-down:before { - content: "\f0ab"; -} -.fa-globe:before { - content: "\f0ac"; -} -.fa-wrench:before { - content: "\f0ad"; -} -.fa-tasks:before { - content: "\f0ae"; -} -.fa-filter:before { - content: "\f0b0"; -} -.fa-briefcase:before { - content: "\f0b1"; -} -.fa-arrows-alt:before { - content: "\f0b2"; -} -.fa-group:before, -.fa-users:before { - content: "\f0c0"; -} -.fa-chain:before, -.fa-link:before { - content: "\f0c1"; -} -.fa-cloud:before { - content: "\f0c2"; -} -.fa-flask:before { - content: "\f0c3"; -} -.fa-cut:before, -.fa-scissors:before { - content: "\f0c4"; -} -.fa-copy:before, -.fa-files-o:before { - content: "\f0c5"; -} -.fa-paperclip:before { - content: "\f0c6"; -} -.fa-save:before, -.fa-floppy-o:before { - content: "\f0c7"; -} -.fa-square:before { - content: "\f0c8"; -} -.fa-navicon:before, -.fa-reorder:before, -.fa-bars:before { - content: "\f0c9"; -} -.fa-list-ul:before { - content: "\f0ca"; -} -.fa-list-ol:before { - content: "\f0cb"; -} -.fa-strikethrough:before { - content: "\f0cc"; -} -.fa-underline:before { - content: "\f0cd"; -} -.fa-table:before { - content: "\f0ce"; -} -.fa-magic:before { - content: "\f0d0"; -} -.fa-truck:before { - content: "\f0d1"; -} -.fa-pinterest:before { - content: "\f0d2"; -} -.fa-pinterest-square:before { - content: "\f0d3"; -} -.fa-google-plus-square:before { - content: "\f0d4"; -} -.fa-google-plus:before { - content: "\f0d5"; -} -.fa-money:before { - content: "\f0d6"; -} -.fa-caret-down:before { - content: "\f0d7"; -} -.fa-caret-up:before { - content: "\f0d8"; -} -.fa-caret-left:before { - content: "\f0d9"; -} -.fa-caret-right:before { - content: "\f0da"; -} -.fa-columns:before { - content: "\f0db"; -} -.fa-unsorted:before, -.fa-sort:before { - content: "\f0dc"; -} -.fa-sort-down:before, -.fa-sort-desc:before { - content: "\f0dd"; -} -.fa-sort-up:before, -.fa-sort-asc:before { - content: "\f0de"; -} -.fa-envelope:before { - content: "\f0e0"; -} -.fa-linkedin:before { - content: "\f0e1"; -} -.fa-rotate-left:before, -.fa-undo:before { - content: "\f0e2"; -} -.fa-legal:before, -.fa-gavel:before { - content: "\f0e3"; -} -.fa-dashboard:before, -.fa-tachometer:before { - content: "\f0e4"; -} -.fa-comment-o:before { - content: "\f0e5"; -} -.fa-comments-o:before { - content: "\f0e6"; -} -.fa-flash:before, -.fa-bolt:before { - content: "\f0e7"; -} -.fa-sitemap:before { - content: "\f0e8"; -} -.fa-umbrella:before { - content: "\f0e9"; -} -.fa-paste:before, -.fa-clipboard:before { - content: "\f0ea"; -} -.fa-lightbulb-o:before { - content: "\f0eb"; -} -.fa-exchange:before { - content: "\f0ec"; -} -.fa-cloud-download:before { - content: "\f0ed"; -} -.fa-cloud-upload:before { - content: "\f0ee"; -} -.fa-user-md:before { - content: "\f0f0"; -} -.fa-stethoscope:before { - content: "\f0f1"; -} -.fa-suitcase:before { - content: "\f0f2"; -} -.fa-bell-o:before { - content: "\f0a2"; -} -.fa-coffee:before { - content: "\f0f4"; -} -.fa-cutlery:before { - content: "\f0f5"; -} -.fa-file-text-o:before { - content: "\f0f6"; -} -.fa-building-o:before { - content: "\f0f7"; -} -.fa-hospital-o:before { - content: "\f0f8"; -} -.fa-ambulance:before { - content: "\f0f9"; -} -.fa-medkit:before { - content: "\f0fa"; -} -.fa-fighter-jet:before { - content: "\f0fb"; -} -.fa-beer:before { - content: "\f0fc"; -} -.fa-h-square:before { - content: "\f0fd"; -} -.fa-plus-square:before { - content: "\f0fe"; -} -.fa-angle-double-left:before { - content: "\f100"; -} -.fa-angle-double-right:before { - content: "\f101"; -} -.fa-angle-double-up:before { - content: "\f102"; -} -.fa-angle-double-down:before { - content: "\f103"; -} -.fa-angle-left:before { - content: "\f104"; -} -.fa-angle-right:before { - content: "\f105"; -} -.fa-angle-up:before { - content: "\f106"; -} -.fa-angle-down:before { - content: "\f107"; -} -.fa-desktop:before { - content: "\f108"; -} -.fa-laptop:before { - content: "\f109"; -} -.fa-tablet:before { - content: "\f10a"; -} -.fa-mobile-phone:before, -.fa-mobile:before { - content: "\f10b"; -} -.fa-circle-o:before { - content: "\f10c"; -} -.fa-quote-left:before { - content: "\f10d"; -} -.fa-quote-right:before { - content: "\f10e"; -} -.fa-spinner:before { - content: "\f110"; -} -.fa-circle:before { - content: "\f111"; -} -.fa-mail-reply:before, -.fa-reply:before { - content: "\f112"; -} -.fa-github-alt:before { - content: "\f113"; -} -.fa-folder-o:before { - content: "\f114"; -} -.fa-folder-open-o:before { - content: "\f115"; -} -.fa-smile-o:before { - content: "\f118"; -} -.fa-frown-o:before { - content: "\f119"; -} -.fa-meh-o:before { - content: "\f11a"; -} -.fa-gamepad:before { - content: "\f11b"; -} -.fa-keyboard-o:before { - content: "\f11c"; -} -.fa-flag-o:before { - content: "\f11d"; -} -.fa-flag-checkered:before { - content: "\f11e"; -} -.fa-terminal:before { - content: "\f120"; -} -.fa-code:before { - content: "\f121"; -} -.fa-mail-reply-all:before, -.fa-reply-all:before { - content: "\f122"; -} -.fa-star-half-empty:before, -.fa-star-half-full:before, -.fa-star-half-o:before { - content: "\f123"; -} -.fa-location-arrow:before { - content: "\f124"; -} -.fa-crop:before { - content: "\f125"; -} -.fa-code-fork:before { - content: "\f126"; -} -.fa-unlink:before, -.fa-chain-broken:before { - content: "\f127"; -} -.fa-question:before { - content: "\f128"; -} -.fa-info:before { - content: "\f129"; -} -.fa-exclamation:before { - content: "\f12a"; -} -.fa-superscript:before { - content: "\f12b"; -} -.fa-subscript:before { - content: "\f12c"; -} -.fa-eraser:before { - content: "\f12d"; -} -.fa-puzzle-piece:before { - content: "\f12e"; -} -.fa-microphone:before { - content: "\f130"; -} -.fa-microphone-slash:before { - content: "\f131"; -} -.fa-shield:before { - content: "\f132"; -} -.fa-calendar-o:before { - content: "\f133"; -} -.fa-fire-extinguisher:before { - content: "\f134"; -} -.fa-rocket:before { - content: "\f135"; -} -.fa-maxcdn:before { - content: "\f136"; -} -.fa-chevron-circle-left:before { - content: "\f137"; -} -.fa-chevron-circle-right:before { - content: "\f138"; -} -.fa-chevron-circle-up:before { - content: "\f139"; -} -.fa-chevron-circle-down:before { - content: "\f13a"; -} -.fa-html5:before { - content: "\f13b"; -} -.fa-css3:before { - content: "\f13c"; -} -.fa-anchor:before { - content: "\f13d"; -} -.fa-unlock-alt:before { - content: "\f13e"; -} -.fa-bullseye:before { - content: "\f140"; -} -.fa-ellipsis-h:before { - content: "\f141"; -} -.fa-ellipsis-v:before { - content: "\f142"; -} -.fa-rss-square:before { - content: "\f143"; -} -.fa-play-circle:before { - content: "\f144"; -} -.fa-ticket:before { - content: "\f145"; -} -.fa-minus-square:before { - content: "\f146"; -} -.fa-minus-square-o:before { - content: "\f147"; -} -.fa-level-up:before { - content: "\f148"; -} -.fa-level-down:before { - content: "\f149"; -} -.fa-check-square:before { - content: "\f14a"; -} -.fa-pencil-square:before { - content: "\f14b"; -} -.fa-external-link-square:before { - content: "\f14c"; -} -.fa-share-square:before { - content: "\f14d"; -} -.fa-compass:before { - content: "\f14e"; -} -.fa-toggle-down:before, -.fa-caret-square-o-down:before { - content: "\f150"; -} -.fa-toggle-up:before, -.fa-caret-square-o-up:before { - content: "\f151"; -} -.fa-toggle-right:before, -.fa-caret-square-o-right:before { - content: "\f152"; -} -.fa-euro:before, -.fa-eur:before { - content: "\f153"; -} -.fa-gbp:before { - content: "\f154"; -} -.fa-dollar:before, -.fa-usd:before { - content: "\f155"; -} -.fa-rupee:before, -.fa-inr:before { - content: "\f156"; -} -.fa-cny:before, -.fa-rmb:before, -.fa-yen:before, -.fa-jpy:before { - content: "\f157"; -} -.fa-ruble:before, -.fa-rouble:before, -.fa-rub:before { - content: "\f158"; -} -.fa-won:before, -.fa-krw:before { - content: "\f159"; -} -.fa-bitcoin:before, -.fa-btc:before { - content: "\f15a"; -} -.fa-file:before { - content: "\f15b"; -} -.fa-file-text:before { - content: "\f15c"; -} -.fa-sort-alpha-asc:before { - content: "\f15d"; -} -.fa-sort-alpha-desc:before { - content: "\f15e"; -} -.fa-sort-amount-asc:before { - content: "\f160"; -} -.fa-sort-amount-desc:before { - content: "\f161"; -} -.fa-sort-numeric-asc:before { - content: "\f162"; -} -.fa-sort-numeric-desc:before { - content: "\f163"; -} -.fa-thumbs-up:before { - content: "\f164"; -} -.fa-thumbs-down:before { - content: "\f165"; -} -.fa-youtube-square:before { - content: "\f166"; -} -.fa-youtube:before { - content: "\f167"; -} -.fa-xing:before { - content: "\f168"; -} -.fa-xing-square:before { - content: "\f169"; -} -.fa-youtube-play:before { - content: "\f16a"; -} -.fa-dropbox:before { - content: "\f16b"; -} -.fa-stack-overflow:before { - content: "\f16c"; -} -.fa-instagram:before { - content: "\f16d"; -} -.fa-flickr:before { - content: "\f16e"; -} -.fa-adn:before { - content: "\f170"; -} -.fa-bitbucket:before { - content: "\f171"; -} -.fa-bitbucket-square:before { - content: "\f172"; -} -.fa-tumblr:before { - content: "\f173"; -} -.fa-tumblr-square:before { - content: "\f174"; -} -.fa-long-arrow-down:before { - content: "\f175"; -} -.fa-long-arrow-up:before { - content: "\f176"; -} -.fa-long-arrow-left:before { - content: "\f177"; -} -.fa-long-arrow-right:before { - content: "\f178"; -} -.fa-apple:before { - content: "\f179"; -} -.fa-windows:before { - content: "\f17a"; -} -.fa-android:before { - content: "\f17b"; -} -.fa-linux:before { - content: "\f17c"; -} -.fa-dribbble:before { - content: "\f17d"; -} -.fa-skype:before { - content: "\f17e"; -} -.fa-foursquare:before { - content: "\f180"; -} -.fa-trello:before { - content: "\f181"; -} -.fa-female:before { - content: "\f182"; -} -.fa-male:before { - content: "\f183"; -} -.fa-gittip:before, -.fa-gratipay:before { - content: "\f184"; -} -.fa-sun-o:before { - content: "\f185"; -} -.fa-moon-o:before { - content: "\f186"; -} -.fa-archive:before { - content: "\f187"; -} -.fa-bug:before { - content: "\f188"; -} -.fa-vk:before { - content: "\f189"; -} -.fa-weibo:before { - content: "\f18a"; -} -.fa-renren:before { - content: "\f18b"; -} -.fa-pagelines:before { - content: "\f18c"; -} -.fa-stack-exchange:before { - content: "\f18d"; -} -.fa-arrow-circle-o-right:before { - content: "\f18e"; -} -.fa-arrow-circle-o-left:before { - content: "\f190"; -} -.fa-toggle-left:before, -.fa-caret-square-o-left:before { - content: "\f191"; -} -.fa-dot-circle-o:before { - content: "\f192"; -} -.fa-wheelchair:before { - content: "\f193"; -} -.fa-vimeo-square:before { - content: "\f194"; -} -.fa-turkish-lira:before, -.fa-try:before { - content: "\f195"; -} -.fa-plus-square-o:before { - content: "\f196"; -} -.fa-space-shuttle:before { - content: "\f197"; -} -.fa-slack:before { - content: "\f198"; -} -.fa-envelope-square:before { - content: "\f199"; -} -.fa-wordpress:before { - content: "\f19a"; -} -.fa-openid:before { - content: "\f19b"; -} -.fa-institution:before, -.fa-bank:before, -.fa-university:before { - content: "\f19c"; -} -.fa-mortar-board:before, -.fa-graduation-cap:before { - content: "\f19d"; -} -.fa-yahoo:before { - content: "\f19e"; -} -.fa-google:before { - content: "\f1a0"; -} -.fa-reddit:before { - content: "\f1a1"; -} -.fa-reddit-square:before { - content: "\f1a2"; -} -.fa-stumbleupon-circle:before { - content: "\f1a3"; -} -.fa-stumbleupon:before { - content: "\f1a4"; -} -.fa-delicious:before { - content: "\f1a5"; -} -.fa-digg:before { - content: "\f1a6"; -} -.fa-pied-piper:before { - content: "\f1a7"; -} -.fa-pied-piper-alt:before { - content: "\f1a8"; -} -.fa-drupal:before { - content: "\f1a9"; -} -.fa-joomla:before { - content: "\f1aa"; -} -.fa-language:before { - content: "\f1ab"; -} -.fa-fax:before { - content: "\f1ac"; -} -.fa-building:before { - content: "\f1ad"; -} -.fa-child:before { - content: "\f1ae"; -} -.fa-paw:before { - content: "\f1b0"; -} -.fa-spoon:before { - content: "\f1b1"; -} -.fa-cube:before { - content: "\f1b2"; -} -.fa-cubes:before { - content: "\f1b3"; -} -.fa-behance:before { - content: "\f1b4"; -} -.fa-behance-square:before { - content: "\f1b5"; -} -.fa-steam:before { - content: "\f1b6"; -} -.fa-steam-square:before { - content: "\f1b7"; -} -.fa-recycle:before { - content: "\f1b8"; -} -.fa-automobile:before, -.fa-car:before { - content: "\f1b9"; -} -.fa-cab:before, -.fa-taxi:before { - content: "\f1ba"; -} -.fa-tree:before { - content: "\f1bb"; -} -.fa-spotify:before { - content: "\f1bc"; -} -.fa-deviantart:before { - content: "\f1bd"; -} -.fa-soundcloud:before { - content: "\f1be"; -} -.fa-database:before { - content: "\f1c0"; -} -.fa-file-pdf-o:before { - content: "\f1c1"; -} -.fa-file-word-o:before { - content: "\f1c2"; -} -.fa-file-excel-o:before { - content: "\f1c3"; -} -.fa-file-powerpoint-o:before { - content: "\f1c4"; -} -.fa-file-photo-o:before, -.fa-file-picture-o:before, -.fa-file-image-o:before { - content: "\f1c5"; -} -.fa-file-zip-o:before, -.fa-file-archive-o:before { - content: "\f1c6"; -} -.fa-file-sound-o:before, -.fa-file-audio-o:before { - content: "\f1c7"; -} -.fa-file-movie-o:before, -.fa-file-video-o:before { - content: "\f1c8"; -} -.fa-file-code-o:before { - content: "\f1c9"; -} -.fa-vine:before { - content: "\f1ca"; -} -.fa-codepen:before { - content: "\f1cb"; -} -.fa-jsfiddle:before { - content: "\f1cc"; -} -.fa-life-bouy:before, -.fa-life-buoy:before, -.fa-life-saver:before, -.fa-support:before, -.fa-life-ring:before { - content: "\f1cd"; -} -.fa-circle-o-notch:before { - content: "\f1ce"; -} -.fa-ra:before, -.fa-rebel:before { - content: "\f1d0"; -} -.fa-ge:before, -.fa-empire:before { - content: "\f1d1"; -} -.fa-git-square:before { - content: "\f1d2"; -} -.fa-git:before { - content: "\f1d3"; -} -.fa-hacker-news:before { - content: "\f1d4"; -} -.fa-tencent-weibo:before { - content: "\f1d5"; -} -.fa-qq:before { - content: "\f1d6"; -} -.fa-wechat:before, -.fa-weixin:before { - content: "\f1d7"; -} -.fa-send:before, -.fa-paper-plane:before { - content: "\f1d8"; -} -.fa-send-o:before, -.fa-paper-plane-o:before { - content: "\f1d9"; -} -.fa-history:before { - content: "\f1da"; -} -.fa-genderless:before, -.fa-circle-thin:before { - content: "\f1db"; -} -.fa-header:before { - content: "\f1dc"; -} -.fa-paragraph:before { - content: "\f1dd"; -} -.fa-sliders:before { - content: "\f1de"; -} -.fa-share-alt:before { - content: "\f1e0"; -} -.fa-share-alt-square:before { - content: "\f1e1"; -} -.fa-bomb:before { - content: "\f1e2"; -} -.fa-soccer-ball-o:before, -.fa-futbol-o:before { - content: "\f1e3"; -} -.fa-tty:before { - content: "\f1e4"; -} -.fa-binoculars:before { - content: "\f1e5"; -} -.fa-plug:before { - content: "\f1e6"; -} -.fa-slideshare:before { - content: "\f1e7"; -} -.fa-twitch:before { - content: "\f1e8"; -} -.fa-yelp:before { - content: "\f1e9"; -} -.fa-newspaper-o:before { - content: "\f1ea"; -} -.fa-wifi:before { - content: "\f1eb"; -} -.fa-calculator:before { - content: "\f1ec"; -} -.fa-paypal:before { - content: "\f1ed"; -} -.fa-google-wallet:before { - content: "\f1ee"; -} -.fa-cc-visa:before { - content: "\f1f0"; -} -.fa-cc-mastercard:before { - content: "\f1f1"; -} -.fa-cc-discover:before { - content: "\f1f2"; -} -.fa-cc-amex:before { - content: "\f1f3"; -} -.fa-cc-paypal:before { - content: "\f1f4"; -} -.fa-cc-stripe:before { - content: "\f1f5"; -} -.fa-bell-slash:before { - content: "\f1f6"; -} -.fa-bell-slash-o:before { - content: "\f1f7"; -} -.fa-trash:before { - content: "\f1f8"; -} -.fa-copyright:before { - content: "\f1f9"; -} -.fa-at:before { - content: "\f1fa"; -} -.fa-eyedropper:before { - content: "\f1fb"; -} -.fa-paint-brush:before { - content: "\f1fc"; -} -.fa-birthday-cake:before { - content: "\f1fd"; -} -.fa-area-chart:before { - content: "\f1fe"; -} -.fa-pie-chart:before { - content: "\f200"; -} -.fa-line-chart:before { - content: "\f201"; -} -.fa-lastfm:before { - content: "\f202"; -} -.fa-lastfm-square:before { - content: "\f203"; -} -.fa-toggle-off:before { - content: "\f204"; -} -.fa-toggle-on:before { - content: "\f205"; -} -.fa-bicycle:before { - content: "\f206"; -} -.fa-bus:before { - content: "\f207"; -} -.fa-ioxhost:before { - content: "\f208"; -} -.fa-angellist:before { - content: "\f209"; -} -.fa-cc:before { - content: "\f20a"; -} -.fa-shekel:before, -.fa-sheqel:before, -.fa-ils:before { - content: "\f20b"; -} -.fa-meanpath:before { - content: "\f20c"; -} -.fa-buysellads:before { - content: "\f20d"; -} -.fa-connectdevelop:before { - content: "\f20e"; -} -.fa-dashcube:before { - content: "\f210"; -} -.fa-forumbee:before { - content: "\f211"; -} -.fa-leanpub:before { - content: "\f212"; -} -.fa-sellsy:before { - content: "\f213"; -} -.fa-shirtsinbulk:before { - content: "\f214"; -} -.fa-simplybuilt:before { - content: "\f215"; -} -.fa-skyatlas:before { - content: "\f216"; -} -.fa-cart-plus:before { - content: "\f217"; -} -.fa-cart-arrow-down:before { - content: "\f218"; -} -.fa-diamond:before { - content: "\f219"; -} -.fa-ship:before { - content: "\f21a"; -} -.fa-user-secret:before { - content: "\f21b"; -} -.fa-motorcycle:before { - content: "\f21c"; -} -.fa-street-view:before { - content: "\f21d"; -} -.fa-heartbeat:before { - content: "\f21e"; -} -.fa-venus:before { - content: "\f221"; -} -.fa-mars:before { - content: "\f222"; -} -.fa-mercury:before { - content: "\f223"; -} -.fa-transgender:before { - content: "\f224"; -} -.fa-transgender-alt:before { - content: "\f225"; -} -.fa-venus-double:before { - content: "\f226"; -} -.fa-mars-double:before { - content: "\f227"; -} -.fa-venus-mars:before { - content: "\f228"; -} -.fa-mars-stroke:before { - content: "\f229"; -} -.fa-mars-stroke-v:before { - content: "\f22a"; -} -.fa-mars-stroke-h:before { - content: "\f22b"; -} -.fa-neuter:before { - content: "\f22c"; -} -.fa-facebook-official:before { - content: "\f230"; -} -.fa-pinterest-p:before { - content: "\f231"; -} -.fa-whatsapp:before { - content: "\f232"; -} -.fa-server:before { - content: "\f233"; -} -.fa-user-plus:before { - content: "\f234"; -} -.fa-user-times:before { - content: "\f235"; -} -.fa-hotel:before, -.fa-bed:before { - content: "\f236"; -} -.fa-viacoin:before { - content: "\f237"; -} -.fa-train:before { - content: "\f238"; -} -.fa-subway:before { - content: "\f239"; -} -.fa-medium:before { - content: "\f23a"; -} + +@import "variables"; +@import "mixins"; +@import "path"; +@import "core"; +@import "larger"; +@import "fixed-width"; +@import "list"; +@import "bordered-pulled"; +@import "animated"; +@import "rotated-flipped"; +@import "stacked"; +@import "icons"; +@import "screen-reader"; diff --git a/public/react/public/css/font-awesome.css b/public/react/public/css/font-awesome.css index 8539c00d..ee906a81 100644 --- a/public/react/public/css/font-awesome.css +++ b/public/react/public/css/font-awesome.css @@ -1,5 +1,2337 @@ /*! - * Font Awesome Free 5.0.13 by @fontawesome - https://fontawesome.com - * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) */ -.fa,.fab,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{animation:a 2s infinite linear}.fa-pulse{animation:a 1s infinite steps(8)}@keyframes a{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";transform:scaleX(-1)}.fa-flip-vertical{transform:scaleY(-1)}.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-horizontal.fa-flip-vertical{transform:scale(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-500px:before{content:"\f26e"}.fa-accessible-icon:before{content:"\f368"}.fa-accusoft:before{content:"\f369"}.fa-address-book:before{content:"\f2b9"}.fa-address-card:before{content:"\f2bb"}.fa-adjust:before{content:"\f042"}.fa-adn:before{content:"\f170"}.fa-adversal:before{content:"\f36a"}.fa-affiliatetheme:before{content:"\f36b"}.fa-algolia:before{content:"\f36c"}.fa-align-center:before{content:"\f037"}.fa-align-justify:before{content:"\f039"}.fa-align-left:before{content:"\f036"}.fa-align-right:before{content:"\f038"}.fa-allergies:before{content:"\f461"}.fa-amazon:before{content:"\f270"}.fa-amazon-pay:before{content:"\f42c"}.fa-ambulance:before{content:"\f0f9"}.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-amilia:before{content:"\f36d"}.fa-anchor:before{content:"\f13d"}.fa-android:before{content:"\f17b"}.fa-angellist:before{content:"\f209"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-down:before{content:"\f107"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angrycreative:before{content:"\f36e"}.fa-angular:before{content:"\f420"}.fa-app-store:before{content:"\f36f"}.fa-app-store-ios:before{content:"\f370"}.fa-apper:before{content:"\f371"}.fa-apple:before{content:"\f179"}.fa-apple-pay:before{content:"\f415"}.fa-archive:before{content:"\f187"}.fa-arrow-alt-circle-down:before{content:"\f358"}.fa-arrow-alt-circle-left:before{content:"\f359"}.fa-arrow-alt-circle-right:before{content:"\f35a"}.fa-arrow-alt-circle-up:before{content:"\f35b"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-down:before{content:"\f063"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrows-alt:before{content:"\f0b2"}.fa-arrows-alt-h:before{content:"\f337"}.fa-arrows-alt-v:before{content:"\f338"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asterisk:before{content:"\f069"}.fa-asymmetrik:before{content:"\f372"}.fa-at:before{content:"\f1fa"}.fa-audible:before{content:"\f373"}.fa-audio-description:before{content:"\f29e"}.fa-autoprefixer:before{content:"\f41c"}.fa-avianex:before{content:"\f374"}.fa-aviato:before{content:"\f421"}.fa-aws:before{content:"\f375"}.fa-backward:before{content:"\f04a"}.fa-balance-scale:before{content:"\f24e"}.fa-ban:before{content:"\f05e"}.fa-band-aid:before{content:"\f462"}.fa-bandcamp:before{content:"\f2d5"}.fa-barcode:before{content:"\f02a"}.fa-bars:before{content:"\f0c9"}.fa-baseball-ball:before{content:"\f433"}.fa-basketball-ball:before{content:"\f434"}.fa-bath:before{content:"\f2cd"}.fa-battery-empty:before{content:"\f244"}.fa-battery-full:before{content:"\f240"}.fa-battery-half:before{content:"\f242"}.fa-battery-quarter:before{content:"\f243"}.fa-battery-three-quarters:before{content:"\f241"}.fa-bed:before{content:"\f236"}.fa-beer:before{content:"\f0fc"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-bell:before{content:"\f0f3"}.fa-bell-slash:before{content:"\f1f6"}.fa-bicycle:before{content:"\f206"}.fa-bimobject:before{content:"\f378"}.fa-binoculars:before{content:"\f1e5"}.fa-birthday-cake:before{content:"\f1fd"}.fa-bitbucket:before{content:"\f171"}.fa-bitcoin:before{content:"\f379"}.fa-bity:before{content:"\f37a"}.fa-black-tie:before{content:"\f27e"}.fa-blackberry:before{content:"\f37b"}.fa-blender:before{content:"\f517"}.fa-blind:before{content:"\f29d"}.fa-blogger:before{content:"\f37c"}.fa-blogger-b:before{content:"\f37d"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-bold:before{content:"\f032"}.fa-bolt:before{content:"\f0e7"}.fa-bomb:before{content:"\f1e2"}.fa-book:before{content:"\f02d"}.fa-book-open:before{content:"\f518"}.fa-bookmark:before{content:"\f02e"}.fa-bowling-ball:before{content:"\f436"}.fa-box:before{content:"\f466"}.fa-box-open:before{content:"\f49e"}.fa-boxes:before{content:"\f468"}.fa-braille:before{content:"\f2a1"}.fa-briefcase:before{content:"\f0b1"}.fa-briefcase-medical:before{content:"\f469"}.fa-broadcast-tower:before{content:"\f519"}.fa-broom:before{content:"\f51a"}.fa-btc:before{content:"\f15a"}.fa-bug:before{content:"\f188"}.fa-building:before{content:"\f1ad"}.fa-bullhorn:before{content:"\f0a1"}.fa-bullseye:before{content:"\f140"}.fa-burn:before{content:"\f46a"}.fa-buromobelexperte:before{content:"\f37f"}.fa-bus:before{content:"\f207"}.fa-buysellads:before{content:"\f20d"}.fa-calculator:before{content:"\f1ec"}.fa-calendar:before{content:"\f133"}.fa-calendar-alt:before{content:"\f073"}.fa-calendar-check:before{content:"\f274"}.fa-calendar-minus:before{content:"\f272"}.fa-calendar-plus:before{content:"\f271"}.fa-calendar-times:before{content:"\f273"}.fa-camera:before{content:"\f030"}.fa-camera-retro:before{content:"\f083"}.fa-capsules:before{content:"\f46b"}.fa-car:before{content:"\f1b9"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-caret-square-down:before{content:"\f150"}.fa-caret-square-left:before{content:"\f191"}.fa-caret-square-right:before{content:"\f152"}.fa-caret-square-up:before{content:"\f151"}.fa-caret-up:before{content:"\f0d8"}.fa-cart-arrow-down:before{content:"\f218"}.fa-cart-plus:before{content:"\f217"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-apple-pay:before{content:"\f416"}.fa-cc-diners-club:before{content:"\f24c"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-cc-visa:before{content:"\f1f0"}.fa-centercode:before{content:"\f380"}.fa-certificate:before{content:"\f0a3"}.fa-chalkboard:before{content:"\f51b"}.fa-chalkboard-teacher:before{content:"\f51c"}.fa-chart-area:before{content:"\f1fe"}.fa-chart-bar:before{content:"\f080"}.fa-chart-line:before{content:"\f201"}.fa-chart-pie:before{content:"\f200"}.fa-check:before{content:"\f00c"}.fa-check-circle:before{content:"\f058"}.fa-check-square:before{content:"\f14a"}.fa-chess:before{content:"\f439"}.fa-chess-bishop:before{content:"\f43a"}.fa-chess-board:before{content:"\f43c"}.fa-chess-king:before{content:"\f43f"}.fa-chess-knight:before{content:"\f441"}.fa-chess-pawn:before{content:"\f443"}.fa-chess-queen:before{content:"\f445"}.fa-chess-rook:before{content:"\f447"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-down:before{content:"\f078"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-chevron-up:before{content:"\f077"}.fa-child:before{content:"\f1ae"}.fa-chrome:before{content:"\f268"}.fa-church:before{content:"\f51d"}.fa-circle:before{content:"\f111"}.fa-circle-notch:before{content:"\f1ce"}.fa-clipboard:before{content:"\f328"}.fa-clipboard-check:before{content:"\f46c"}.fa-clipboard-list:before{content:"\f46d"}.fa-clock:before{content:"\f017"}.fa-clone:before{content:"\f24d"}.fa-closed-captioning:before{content:"\f20a"}.fa-cloud:before{content:"\f0c2"}.fa-cloud-download-alt:before{content:"\f381"}.fa-cloud-upload-alt:before{content:"\f382"}.fa-cloudscale:before{content:"\f383"}.fa-cloudsmith:before{content:"\f384"}.fa-cloudversify:before{content:"\f385"}.fa-code:before{content:"\f121"}.fa-code-branch:before{content:"\f126"}.fa-codepen:before{content:"\f1cb"}.fa-codiepie:before{content:"\f284"}.fa-coffee:before{content:"\f0f4"}.fa-cog:before{content:"\f013"}.fa-cogs:before{content:"\f085"}.fa-coins:before{content:"\f51e"}.fa-columns:before{content:"\f0db"}.fa-comment:before{content:"\f075"}.fa-comment-alt:before{content:"\f27a"}.fa-comment-dots:before{content:"\f4ad"}.fa-comment-slash:before{content:"\f4b3"}.fa-comments:before{content:"\f086"}.fa-compact-disc:before{content:"\f51f"}.fa-compass:before{content:"\f14e"}.fa-compress:before{content:"\f066"}.fa-connectdevelop:before{content:"\f20e"}.fa-contao:before{content:"\f26d"}.fa-copy:before{content:"\f0c5"}.fa-copyright:before{content:"\f1f9"}.fa-couch:before{content:"\f4b8"}.fa-cpanel:before{content:"\f388"}.fa-creative-commons:before{content:"\f25e"}.fa-creative-commons-by:before{content:"\f4e7"}.fa-creative-commons-nc:before{content:"\f4e8"}.fa-creative-commons-nc-eu:before{content:"\f4e9"}.fa-creative-commons-nc-jp:before{content:"\f4ea"}.fa-creative-commons-nd:before{content:"\f4eb"}.fa-creative-commons-pd:before{content:"\f4ec"}.fa-creative-commons-pd-alt:before{content:"\f4ed"}.fa-creative-commons-remix:before{content:"\f4ee"}.fa-creative-commons-sa:before{content:"\f4ef"}.fa-creative-commons-sampling:before{content:"\f4f0"}.fa-creative-commons-sampling-plus:before{content:"\f4f1"}.fa-creative-commons-share:before{content:"\f4f2"}.fa-credit-card:before{content:"\f09d"}.fa-crop:before{content:"\f125"}.fa-crosshairs:before{content:"\f05b"}.fa-crow:before{content:"\f520"}.fa-crown:before{content:"\f521"}.fa-css3:before{content:"\f13c"}.fa-css3-alt:before{content:"\f38b"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-cut:before{content:"\f0c4"}.fa-cuttlefish:before{content:"\f38c"}.fa-d-and-d:before{content:"\f38d"}.fa-dashcube:before{content:"\f210"}.fa-database:before{content:"\f1c0"}.fa-deaf:before{content:"\f2a4"}.fa-delicious:before{content:"\f1a5"}.fa-deploydog:before{content:"\f38e"}.fa-deskpro:before{content:"\f38f"}.fa-desktop:before{content:"\f108"}.fa-deviantart:before{content:"\f1bd"}.fa-diagnoses:before{content:"\f470"}.fa-dice:before{content:"\f522"}.fa-dice-five:before{content:"\f523"}.fa-dice-four:before{content:"\f524"}.fa-dice-one:before{content:"\f525"}.fa-dice-six:before{content:"\f526"}.fa-dice-three:before{content:"\f527"}.fa-dice-two:before{content:"\f528"}.fa-digg:before{content:"\f1a6"}.fa-digital-ocean:before{content:"\f391"}.fa-discord:before{content:"\f392"}.fa-discourse:before{content:"\f393"}.fa-divide:before{content:"\f529"}.fa-dna:before{content:"\f471"}.fa-dochub:before{content:"\f394"}.fa-docker:before{content:"\f395"}.fa-dollar-sign:before{content:"\f155"}.fa-dolly:before{content:"\f472"}.fa-dolly-flatbed:before{content:"\f474"}.fa-donate:before{content:"\f4b9"}.fa-door-closed:before{content:"\f52a"}.fa-door-open:before{content:"\f52b"}.fa-dot-circle:before{content:"\f192"}.fa-dove:before{content:"\f4ba"}.fa-download:before{content:"\f019"}.fa-draft2digital:before{content:"\f396"}.fa-dribbble:before{content:"\f17d"}.fa-dribbble-square:before{content:"\f397"}.fa-dropbox:before{content:"\f16b"}.fa-drupal:before{content:"\f1a9"}.fa-dumbbell:before{content:"\f44b"}.fa-dyalog:before{content:"\f399"}.fa-earlybirds:before{content:"\f39a"}.fa-ebay:before{content:"\f4f4"}.fa-edge:before{content:"\f282"}.fa-edit:before{content:"\f044"}.fa-eject:before{content:"\f052"}.fa-elementor:before{content:"\f430"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-ember:before{content:"\f423"}.fa-empire:before{content:"\f1d1"}.fa-envelope:before{content:"\f0e0"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-square:before{content:"\f199"}.fa-envira:before{content:"\f299"}.fa-equals:before{content:"\f52c"}.fa-eraser:before{content:"\f12d"}.fa-erlang:before{content:"\f39d"}.fa-ethereum:before{content:"\f42e"}.fa-etsy:before{content:"\f2d7"}.fa-euro-sign:before{content:"\f153"}.fa-exchange-alt:before{content:"\f362"}.fa-exclamation:before{content:"\f12a"}.fa-exclamation-circle:before{content:"\f06a"}.fa-exclamation-triangle:before{content:"\f071"}.fa-expand:before{content:"\f065"}.fa-expand-arrows-alt:before{content:"\f31e"}.fa-expeditedssl:before{content:"\f23e"}.fa-external-link-alt:before{content:"\f35d"}.fa-external-link-square-alt:before{content:"\f360"}.fa-eye:before{content:"\f06e"}.fa-eye-dropper:before{content:"\f1fb"}.fa-eye-slash:before{content:"\f070"}.fa-facebook:before{content:"\f09a"}.fa-facebook-f:before{content:"\f39e"}.fa-facebook-messenger:before{content:"\f39f"}.fa-facebook-square:before{content:"\f082"}.fa-fast-backward:before{content:"\f049"}.fa-fast-forward:before{content:"\f050"}.fa-fax:before{content:"\f1ac"}.fa-feather:before{content:"\f52d"}.fa-female:before{content:"\f182"}.fa-fighter-jet:before{content:"\f0fb"}.fa-file:before{content:"\f15b"}.fa-file-alt:before{content:"\f15c"}.fa-file-archive:before{content:"\f1c6"}.fa-file-audio:before{content:"\f1c7"}.fa-file-code:before{content:"\f1c9"}.fa-file-excel:before{content:"\f1c3"}.fa-file-image:before{content:"\f1c5"}.fa-file-medical:before{content:"\f477"}.fa-file-medical-alt:before{content:"\f478"}.fa-file-pdf:before{content:"\f1c1"}.fa-file-powerpoint:before{content:"\f1c4"}.fa-file-video:before{content:"\f1c8"}.fa-file-word:before{content:"\f1c2"}.fa-film:before{content:"\f008"}.fa-filter:before{content:"\f0b0"}.fa-fire:before{content:"\f06d"}.fa-fire-extinguisher:before{content:"\f134"}.fa-firefox:before{content:"\f269"}.fa-first-aid:before{content:"\f479"}.fa-first-order:before{content:"\f2b0"}.fa-first-order-alt:before{content:"\f50a"}.fa-firstdraft:before{content:"\f3a1"}.fa-flag:before{content:"\f024"}.fa-flag-checkered:before{content:"\f11e"}.fa-flask:before{content:"\f0c3"}.fa-flickr:before{content:"\f16e"}.fa-flipboard:before{content:"\f44d"}.fa-fly:before{content:"\f417"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-font:before{content:"\f031"}.fa-font-awesome:before{content:"\f2b4"}.fa-font-awesome-alt:before{content:"\f35c"}.fa-font-awesome-flag:before{content:"\f425"}.fa-font-awesome-logo-full:before{content:"\f4e6"}.fa-fonticons:before{content:"\f280"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-football-ball:before{content:"\f44e"}.fa-fort-awesome:before{content:"\f286"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-forumbee:before{content:"\f211"}.fa-forward:before{content:"\f04e"}.fa-foursquare:before{content:"\f180"}.fa-free-code-camp:before{content:"\f2c5"}.fa-freebsd:before{content:"\f3a4"}.fa-frog:before{content:"\f52e"}.fa-frown:before{content:"\f119"}.fa-fulcrum:before{content:"\f50b"}.fa-futbol:before{content:"\f1e3"}.fa-galactic-republic:before{content:"\f50c"}.fa-galactic-senate:before{content:"\f50d"}.fa-gamepad:before{content:"\f11b"}.fa-gas-pump:before{content:"\f52f"}.fa-gavel:before{content:"\f0e3"}.fa-gem:before{content:"\f3a5"}.fa-genderless:before{content:"\f22d"}.fa-get-pocket:before{content:"\f265"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-gift:before{content:"\f06b"}.fa-git:before{content:"\f1d3"}.fa-git-square:before{content:"\f1d2"}.fa-github:before{content:"\f09b"}.fa-github-alt:before{content:"\f113"}.fa-github-square:before{content:"\f092"}.fa-gitkraken:before{content:"\f3a6"}.fa-gitlab:before{content:"\f296"}.fa-gitter:before{content:"\f426"}.fa-glass-martini:before{content:"\f000"}.fa-glasses:before{content:"\f530"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-globe:before{content:"\f0ac"}.fa-gofore:before{content:"\f3a7"}.fa-golf-ball:before{content:"\f450"}.fa-goodreads:before{content:"\f3a8"}.fa-goodreads-g:before{content:"\f3a9"}.fa-google:before{content:"\f1a0"}.fa-google-drive:before{content:"\f3aa"}.fa-google-play:before{content:"\f3ab"}.fa-google-plus:before{content:"\f2b3"}.fa-google-plus-g:before{content:"\f0d5"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-wallet:before{content:"\f1ee"}.fa-graduation-cap:before{content:"\f19d"}.fa-gratipay:before{content:"\f184"}.fa-grav:before{content:"\f2d6"}.fa-greater-than:before{content:"\f531"}.fa-greater-than-equal:before{content:"\f532"}.fa-gripfire:before{content:"\f3ac"}.fa-grunt:before{content:"\f3ad"}.fa-gulp:before{content:"\f3ae"}.fa-h-square:before{content:"\f0fd"}.fa-hacker-news:before{content:"\f1d4"}.fa-hacker-news-square:before{content:"\f3af"}.fa-hand-holding:before{content:"\f4bd"}.fa-hand-holding-heart:before{content:"\f4be"}.fa-hand-holding-usd:before{content:"\f4c0"}.fa-hand-lizard:before{content:"\f258"}.fa-hand-paper:before{content:"\f256"}.fa-hand-peace:before{content:"\f25b"}.fa-hand-point-down:before{content:"\f0a7"}.fa-hand-point-left:before{content:"\f0a5"}.fa-hand-point-right:before{content:"\f0a4"}.fa-hand-point-up:before{content:"\f0a6"}.fa-hand-pointer:before{content:"\f25a"}.fa-hand-rock:before{content:"\f255"}.fa-hand-scissors:before{content:"\f257"}.fa-hand-spock:before{content:"\f259"}.fa-hands:before{content:"\f4c2"}.fa-hands-helping:before{content:"\f4c4"}.fa-handshake:before{content:"\f2b5"}.fa-hashtag:before{content:"\f292"}.fa-hdd:before{content:"\f0a0"}.fa-heading:before{content:"\f1dc"}.fa-headphones:before{content:"\f025"}.fa-heart:before{content:"\f004"}.fa-heartbeat:before{content:"\f21e"}.fa-helicopter:before{content:"\f533"}.fa-hips:before{content:"\f452"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-history:before{content:"\f1da"}.fa-hockey-puck:before{content:"\f453"}.fa-home:before{content:"\f015"}.fa-hooli:before{content:"\f427"}.fa-hospital:before{content:"\f0f8"}.fa-hospital-alt:before{content:"\f47d"}.fa-hospital-symbol:before{content:"\f47e"}.fa-hotjar:before{content:"\f3b1"}.fa-hourglass:before{content:"\f254"}.fa-hourglass-end:before{content:"\f253"}.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-start:before{content:"\f251"}.fa-houzz:before{content:"\f27c"}.fa-html5:before{content:"\f13b"}.fa-hubspot:before{content:"\f3b2"}.fa-i-cursor:before{content:"\f246"}.fa-id-badge:before{content:"\f2c1"}.fa-id-card:before{content:"\f2c2"}.fa-id-card-alt:before{content:"\f47f"}.fa-image:before{content:"\f03e"}.fa-images:before{content:"\f302"}.fa-imdb:before{content:"\f2d8"}.fa-inbox:before{content:"\f01c"}.fa-indent:before{content:"\f03c"}.fa-industry:before{content:"\f275"}.fa-infinity:before{content:"\f534"}.fa-info:before{content:"\f129"}.fa-info-circle:before{content:"\f05a"}.fa-instagram:before{content:"\f16d"}.fa-internet-explorer:before{content:"\f26b"}.fa-ioxhost:before{content:"\f208"}.fa-italic:before{content:"\f033"}.fa-itunes:before{content:"\f3b4"}.fa-itunes-note:before{content:"\f3b5"}.fa-java:before{content:"\f4e4"}.fa-jedi-order:before{content:"\f50e"}.fa-jenkins:before{content:"\f3b6"}.fa-joget:before{content:"\f3b7"}.fa-joomla:before{content:"\f1aa"}.fa-js:before{content:"\f3b8"}.fa-js-square:before{content:"\f3b9"}.fa-jsfiddle:before{content:"\f1cc"}.fa-key:before{content:"\f084"}.fa-keybase:before{content:"\f4f5"}.fa-keyboard:before{content:"\f11c"}.fa-keycdn:before{content:"\f3ba"}.fa-kickstarter:before{content:"\f3bb"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-kiwi-bird:before{content:"\f535"}.fa-korvue:before{content:"\f42f"}.fa-language:before{content:"\f1ab"}.fa-laptop:before{content:"\f109"}.fa-laravel:before{content:"\f3bd"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-leaf:before{content:"\f06c"}.fa-leanpub:before{content:"\f212"}.fa-lemon:before{content:"\f094"}.fa-less:before{content:"\f41d"}.fa-less-than:before{content:"\f536"}.fa-less-than-equal:before{content:"\f537"}.fa-level-down-alt:before{content:"\f3be"}.fa-level-up-alt:before{content:"\f3bf"}.fa-life-ring:before{content:"\f1cd"}.fa-lightbulb:before{content:"\f0eb"}.fa-line:before{content:"\f3c0"}.fa-link:before{content:"\f0c1"}.fa-linkedin:before{content:"\f08c"}.fa-linkedin-in:before{content:"\f0e1"}.fa-linode:before{content:"\f2b8"}.fa-linux:before{content:"\f17c"}.fa-lira-sign:before{content:"\f195"}.fa-list:before{content:"\f03a"}.fa-list-alt:before{content:"\f022"}.fa-list-ol:before{content:"\f0cb"}.fa-list-ul:before{content:"\f0ca"}.fa-location-arrow:before{content:"\f124"}.fa-lock:before{content:"\f023"}.fa-lock-open:before{content:"\f3c1"}.fa-long-arrow-alt-down:before{content:"\f309"}.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-long-arrow-alt-right:before{content:"\f30b"}.fa-long-arrow-alt-up:before{content:"\f30c"}.fa-low-vision:before{content:"\f2a8"}.fa-lyft:before{content:"\f3c3"}.fa-magento:before{content:"\f3c4"}.fa-magic:before{content:"\f0d0"}.fa-magnet:before{content:"\f076"}.fa-male:before{content:"\f183"}.fa-mandalorian:before{content:"\f50f"}.fa-map:before{content:"\f279"}.fa-map-marker:before{content:"\f041"}.fa-map-marker-alt:before{content:"\f3c5"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-mars:before{content:"\f222"}.fa-mars-double:before{content:"\f227"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mastodon:before{content:"\f4f6"}.fa-maxcdn:before{content:"\f136"}.fa-medapps:before{content:"\f3c6"}.fa-medium:before{content:"\f23a"}.fa-medium-m:before{content:"\f3c7"}.fa-medkit:before{content:"\f0fa"}.fa-medrt:before{content:"\f3c8"}.fa-meetup:before{content:"\f2e0"}.fa-meh:before{content:"\f11a"}.fa-memory:before{content:"\f538"}.fa-mercury:before{content:"\f223"}.fa-microchip:before{content:"\f2db"}.fa-microphone:before{content:"\f130"}.fa-microphone-alt:before{content:"\f3c9"}.fa-microphone-alt-slash:before{content:"\f539"}.fa-microphone-slash:before{content:"\f131"}.fa-microsoft:before{content:"\f3ca"}.fa-minus:before{content:"\f068"}.fa-minus-circle:before{content:"\f056"}.fa-minus-square:before{content:"\f146"}.fa-mix:before{content:"\f3cb"}.fa-mixcloud:before{content:"\f289"}.fa-mizuni:before{content:"\f3cc"}.fa-mobile:before{content:"\f10b"}.fa-mobile-alt:before{content:"\f3cd"}.fa-modx:before{content:"\f285"}.fa-monero:before{content:"\f3d0"}.fa-money-bill:before{content:"\f0d6"}.fa-money-bill-alt:before{content:"\f3d1"}.fa-money-bill-wave:before{content:"\f53a"}.fa-money-bill-wave-alt:before{content:"\f53b"}.fa-money-check:before{content:"\f53c"}.fa-money-check-alt:before{content:"\f53d"}.fa-moon:before{content:"\f186"}.fa-motorcycle:before{content:"\f21c"}.fa-mouse-pointer:before{content:"\f245"}.fa-music:before{content:"\f001"}.fa-napster:before{content:"\f3d2"}.fa-neuter:before{content:"\f22c"}.fa-newspaper:before{content:"\f1ea"}.fa-nintendo-switch:before{content:"\f418"}.fa-node:before{content:"\f419"}.fa-node-js:before{content:"\f3d3"}.fa-not-equal:before{content:"\f53e"}.fa-notes-medical:before{content:"\f481"}.fa-npm:before{content:"\f3d4"}.fa-ns8:before{content:"\f3d5"}.fa-nutritionix:before{content:"\f3d6"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-old-republic:before{content:"\f510"}.fa-opencart:before{content:"\f23d"}.fa-openid:before{content:"\f19b"}.fa-opera:before{content:"\f26a"}.fa-optin-monster:before{content:"\f23c"}.fa-osi:before{content:"\f41a"}.fa-outdent:before{content:"\f03b"}.fa-page4:before{content:"\f3d7"}.fa-pagelines:before{content:"\f18c"}.fa-paint-brush:before{content:"\f1fc"}.fa-palette:before{content:"\f53f"}.fa-palfed:before{content:"\f3d8"}.fa-pallet:before{content:"\f482"}.fa-paper-plane:before{content:"\f1d8"}.fa-paperclip:before{content:"\f0c6"}.fa-parachute-box:before{content:"\f4cd"}.fa-paragraph:before{content:"\f1dd"}.fa-parking:before{content:"\f540"}.fa-paste:before{content:"\f0ea"}.fa-patreon:before{content:"\f3d9"}.fa-pause:before{content:"\f04c"}.fa-pause-circle:before{content:"\f28b"}.fa-paw:before{content:"\f1b0"}.fa-paypal:before{content:"\f1ed"}.fa-pen-square:before{content:"\f14b"}.fa-pencil-alt:before{content:"\f303"}.fa-people-carry:before{content:"\f4ce"}.fa-percent:before{content:"\f295"}.fa-percentage:before{content:"\f541"}.fa-periscope:before{content:"\f3da"}.fa-phabricator:before{content:"\f3db"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-phoenix-squadron:before{content:"\f511"}.fa-phone:before{content:"\f095"}.fa-phone-slash:before{content:"\f3dd"}.fa-phone-square:before{content:"\f098"}.fa-phone-volume:before{content:"\f2a0"}.fa-php:before{content:"\f457"}.fa-pied-piper:before{content:"\f2ae"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-piggy-bank:before{content:"\f4d3"}.fa-pills:before{content:"\f484"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-p:before{content:"\f231"}.fa-pinterest-square:before{content:"\f0d3"}.fa-plane:before{content:"\f072"}.fa-play:before{content:"\f04b"}.fa-play-circle:before{content:"\f144"}.fa-playstation:before{content:"\f3df"}.fa-plug:before{content:"\f1e6"}.fa-plus:before{content:"\f067"}.fa-plus-circle:before{content:"\f055"}.fa-plus-square:before{content:"\f0fe"}.fa-podcast:before{content:"\f2ce"}.fa-poo:before{content:"\f2fe"}.fa-portrait:before{content:"\f3e0"}.fa-pound-sign:before{content:"\f154"}.fa-power-off:before{content:"\f011"}.fa-prescription-bottle:before{content:"\f485"}.fa-prescription-bottle-alt:before{content:"\f486"}.fa-print:before{content:"\f02f"}.fa-procedures:before{content:"\f487"}.fa-product-hunt:before{content:"\f288"}.fa-project-diagram:before{content:"\f542"}.fa-pushed:before{content:"\f3e1"}.fa-puzzle-piece:before{content:"\f12e"}.fa-python:before{content:"\f3e2"}.fa-qq:before{content:"\f1d6"}.fa-qrcode:before{content:"\f029"}.fa-question:before{content:"\f128"}.fa-question-circle:before{content:"\f059"}.fa-quidditch:before{content:"\f458"}.fa-quinscape:before{content:"\f459"}.fa-quora:before{content:"\f2c4"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-r-project:before{content:"\f4f7"}.fa-random:before{content:"\f074"}.fa-ravelry:before{content:"\f2d9"}.fa-react:before{content:"\f41b"}.fa-readme:before{content:"\f4d5"}.fa-rebel:before{content:"\f1d0"}.fa-receipt:before{content:"\f543"}.fa-recycle:before{content:"\f1b8"}.fa-red-river:before{content:"\f3e3"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-alien:before{content:"\f281"}.fa-reddit-square:before{content:"\f1a2"}.fa-redo:before{content:"\f01e"}.fa-redo-alt:before{content:"\f2f9"}.fa-registered:before{content:"\f25d"}.fa-rendact:before{content:"\f3e4"}.fa-renren:before{content:"\f18b"}.fa-reply:before{content:"\f3e5"}.fa-reply-all:before{content:"\f122"}.fa-replyd:before{content:"\f3e6"}.fa-researchgate:before{content:"\f4f8"}.fa-resolving:before{content:"\f3e7"}.fa-retweet:before{content:"\f079"}.fa-ribbon:before{content:"\f4d6"}.fa-road:before{content:"\f018"}.fa-robot:before{content:"\f544"}.fa-rocket:before{content:"\f135"}.fa-rocketchat:before{content:"\f3e8"}.fa-rockrms:before{content:"\f3e9"}.fa-rss:before{content:"\f09e"}.fa-rss-square:before{content:"\f143"}.fa-ruble-sign:before{content:"\f158"}.fa-ruler:before{content:"\f545"}.fa-ruler-combined:before{content:"\f546"}.fa-ruler-horizontal:before{content:"\f547"}.fa-ruler-vertical:before{content:"\f548"}.fa-rupee-sign:before{content:"\f156"}.fa-safari:before{content:"\f267"}.fa-sass:before{content:"\f41e"}.fa-save:before{content:"\f0c7"}.fa-schlix:before{content:"\f3ea"}.fa-school:before{content:"\f549"}.fa-screwdriver:before{content:"\f54a"}.fa-scribd:before{content:"\f28a"}.fa-search:before{content:"\f002"}.fa-search-minus:before{content:"\f010"}.fa-search-plus:before{content:"\f00e"}.fa-searchengin:before{content:"\f3eb"}.fa-seedling:before{content:"\f4d8"}.fa-sellcast:before{content:"\f2da"}.fa-sellsy:before{content:"\f213"}.fa-server:before{content:"\f233"}.fa-servicestack:before{content:"\f3ec"}.fa-share:before{content:"\f064"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-share-square:before{content:"\f14d"}.fa-shekel-sign:before{content:"\f20b"}.fa-shield-alt:before{content:"\f3ed"}.fa-ship:before{content:"\f21a"}.fa-shipping-fast:before{content:"\f48b"}.fa-shirtsinbulk:before{content:"\f214"}.fa-shoe-prints:before{content:"\f54b"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-shopping-cart:before{content:"\f07a"}.fa-shower:before{content:"\f2cc"}.fa-sign:before{content:"\f4d9"}.fa-sign-in-alt:before{content:"\f2f6"}.fa-sign-language:before{content:"\f2a7"}.fa-sign-out-alt:before{content:"\f2f5"}.fa-signal:before{content:"\f012"}.fa-simplybuilt:before{content:"\f215"}.fa-sistrix:before{content:"\f3ee"}.fa-sitemap:before{content:"\f0e8"}.fa-sith:before{content:"\f512"}.fa-skull:before{content:"\f54c"}.fa-skyatlas:before{content:"\f216"}.fa-skype:before{content:"\f17e"}.fa-slack:before{content:"\f198"}.fa-slack-hash:before{content:"\f3ef"}.fa-sliders-h:before{content:"\f1de"}.fa-slideshare:before{content:"\f1e7"}.fa-smile:before{content:"\f118"}.fa-smoking:before{content:"\f48d"}.fa-smoking-ban:before{content:"\f54d"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-snowflake:before{content:"\f2dc"}.fa-sort:before{content:"\f0dc"}.fa-sort-alpha-down:before{content:"\f15d"}.fa-sort-alpha-up:before{content:"\f15e"}.fa-sort-amount-down:before{content:"\f160"}.fa-sort-amount-up:before{content:"\f161"}.fa-sort-down:before{content:"\f0dd"}.fa-sort-numeric-down:before{content:"\f162"}.fa-sort-numeric-up:before{content:"\f163"}.fa-sort-up:before{content:"\f0de"}.fa-soundcloud:before{content:"\f1be"}.fa-space-shuttle:before{content:"\f197"}.fa-speakap:before{content:"\f3f3"}.fa-spinner:before{content:"\f110"}.fa-spotify:before{content:"\f1bc"}.fa-square:before{content:"\f0c8"}.fa-square-full:before{content:"\f45c"}.fa-stack-exchange:before{content:"\f18d"}.fa-stack-overflow:before{content:"\f16c"}.fa-star:before{content:"\f005"}.fa-star-half:before{content:"\f089"}.fa-staylinked:before{content:"\f3f5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-steam-symbol:before{content:"\f3f6"}.fa-step-backward:before{content:"\f048"}.fa-step-forward:before{content:"\f051"}.fa-stethoscope:before{content:"\f0f1"}.fa-sticker-mule:before{content:"\f3f7"}.fa-sticky-note:before{content:"\f249"}.fa-stop:before{content:"\f04d"}.fa-stop-circle:before{content:"\f28d"}.fa-stopwatch:before{content:"\f2f2"}.fa-store:before{content:"\f54e"}.fa-store-alt:before{content:"\f54f"}.fa-strava:before{content:"\f428"}.fa-stream:before{content:"\f550"}.fa-street-view:before{content:"\f21d"}.fa-strikethrough:before{content:"\f0cc"}.fa-stripe:before{content:"\f429"}.fa-stripe-s:before{content:"\f42a"}.fa-stroopwafel:before{content:"\f551"}.fa-studiovinari:before{content:"\f3f8"}.fa-stumbleupon:before{content:"\f1a4"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-subscript:before{content:"\f12c"}.fa-subway:before{content:"\f239"}.fa-suitcase:before{content:"\f0f2"}.fa-sun:before{content:"\f185"}.fa-superpowers:before{content:"\f2dd"}.fa-superscript:before{content:"\f12b"}.fa-supple:before{content:"\f3f9"}.fa-sync:before{content:"\f021"}.fa-sync-alt:before{content:"\f2f1"}.fa-syringe:before{content:"\f48e"}.fa-table:before{content:"\f0ce"}.fa-table-tennis:before{content:"\f45d"}.fa-tablet:before{content:"\f10a"}.fa-tablet-alt:before{content:"\f3fa"}.fa-tablets:before{content:"\f490"}.fa-tachometer-alt:before{content:"\f3fd"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-tape:before{content:"\f4db"}.fa-tasks:before{content:"\f0ae"}.fa-taxi:before{content:"\f1ba"}.fa-teamspeak:before{content:"\f4f9"}.fa-telegram:before{content:"\f2c6"}.fa-telegram-plane:before{content:"\f3fe"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-terminal:before{content:"\f120"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-th:before{content:"\f00a"}.fa-th-large:before{content:"\f009"}.fa-th-list:before{content:"\f00b"}.fa-themeisle:before{content:"\f2b2"}.fa-thermometer:before{content:"\f491"}.fa-thermometer-empty:before{content:"\f2cb"}.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thumbs-down:before{content:"\f165"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbtack:before{content:"\f08d"}.fa-ticket-alt:before{content:"\f3ff"}.fa-times:before{content:"\f00d"}.fa-times-circle:before{content:"\f057"}.fa-tint:before{content:"\f043"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-toolbox:before{content:"\f552"}.fa-trade-federation:before{content:"\f513"}.fa-trademark:before{content:"\f25c"}.fa-train:before{content:"\f238"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-trash:before{content:"\f1f8"}.fa-trash-alt:before{content:"\f2ed"}.fa-tree:before{content:"\f1bb"}.fa-trello:before{content:"\f181"}.fa-tripadvisor:before{content:"\f262"}.fa-trophy:before{content:"\f091"}.fa-truck:before{content:"\f0d1"}.fa-truck-loading:before{content:"\f4de"}.fa-truck-moving:before{content:"\f4df"}.fa-tshirt:before{content:"\f553"}.fa-tty:before{content:"\f1e4"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-tv:before{content:"\f26c"}.fa-twitch:before{content:"\f1e8"}.fa-twitter:before{content:"\f099"}.fa-twitter-square:before{content:"\f081"}.fa-typo3:before{content:"\f42b"}.fa-uber:before{content:"\f402"}.fa-uikit:before{content:"\f403"}.fa-umbrella:before{content:"\f0e9"}.fa-underline:before{content:"\f0cd"}.fa-undo:before{content:"\f0e2"}.fa-undo-alt:before{content:"\f2ea"}.fa-uniregistry:before{content:"\f404"}.fa-universal-access:before{content:"\f29a"}.fa-university:before{content:"\f19c"}.fa-unlink:before{content:"\f127"}.fa-unlock:before{content:"\f09c"}.fa-unlock-alt:before{content:"\f13e"}.fa-untappd:before{content:"\f405"}.fa-upload:before{content:"\f093"}.fa-usb:before{content:"\f287"}.fa-user:before{content:"\f007"}.fa-user-alt:before{content:"\f406"}.fa-user-alt-slash:before{content:"\f4fa"}.fa-user-astronaut:before{content:"\f4fb"}.fa-user-check:before{content:"\f4fc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-clock:before{content:"\f4fd"}.fa-user-cog:before{content:"\f4fe"}.fa-user-edit:before{content:"\f4ff"}.fa-user-friends:before{content:"\f500"}.fa-user-graduate:before{content:"\f501"}.fa-user-lock:before{content:"\f502"}.fa-user-md:before{content:"\f0f0"}.fa-user-minus:before{content:"\f503"}.fa-user-ninja:before{content:"\f504"}.fa-user-plus:before{content:"\f234"}.fa-user-secret:before{content:"\f21b"}.fa-user-shield:before{content:"\f505"}.fa-user-slash:before{content:"\f506"}.fa-user-tag:before{content:"\f507"}.fa-user-tie:before{content:"\f508"}.fa-user-times:before{content:"\f235"}.fa-users:before{content:"\f0c0"}.fa-users-cog:before{content:"\f509"}.fa-ussunnah:before{content:"\f407"}.fa-utensil-spoon:before{content:"\f2e5"}.fa-utensils:before{content:"\f2e7"}.fa-vaadin:before{content:"\f408"}.fa-venus:before{content:"\f221"}.fa-venus-double:before{content:"\f226"}.fa-venus-mars:before{content:"\f228"}.fa-viacoin:before{content:"\f237"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-vial:before{content:"\f492"}.fa-vials:before{content:"\f493"}.fa-viber:before{content:"\f409"}.fa-video:before{content:"\f03d"}.fa-video-slash:before{content:"\f4e2"}.fa-vimeo:before{content:"\f40a"}.fa-vimeo-square:before{content:"\f194"}.fa-vimeo-v:before{content:"\f27d"}.fa-vine:before{content:"\f1ca"}.fa-vk:before{content:"\f189"}.fa-vnv:before{content:"\f40b"}.fa-volleyball-ball:before{content:"\f45f"}.fa-volume-down:before{content:"\f027"}.fa-volume-off:before{content:"\f026"}.fa-volume-up:before{content:"\f028"}.fa-vuejs:before{content:"\f41f"}.fa-walking:before{content:"\f554"}.fa-wallet:before{content:"\f555"}.fa-warehouse:before{content:"\f494"}.fa-weibo:before{content:"\f18a"}.fa-weight:before{content:"\f496"}.fa-weixin:before{content:"\f1d7"}.fa-whatsapp:before{content:"\f232"}.fa-whatsapp-square:before{content:"\f40c"}.fa-wheelchair:before{content:"\f193"}.fa-whmcs:before{content:"\f40d"}.fa-wifi:before{content:"\f1eb"}.fa-wikipedia-w:before{content:"\f266"}.fa-window-close:before{content:"\f410"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-windows:before{content:"\f17a"}.fa-wine-glass:before{content:"\f4e3"}.fa-wolf-pack-battalion:before{content:"\f514"}.fa-won-sign:before{content:"\f159"}.fa-wordpress:before{content:"\f19a"}.fa-wordpress-simple:before{content:"\f411"}.fa-wpbeginner:before{content:"\f297"}.fa-wpexplorer:before{content:"\f2de"}.fa-wpforms:before{content:"\f298"}.fa-wrench:before{content:"\f0ad"}.fa-x-ray:before{content:"\f497"}.fa-xbox:before{content:"\f412"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-y-combinator:before{content:"\f23b"}.fa-yahoo:before{content:"\f19e"}.fa-yandex:before{content:"\f413"}.fa-yandex-international:before{content:"\f414"}.fa-yelp:before{content:"\f1e9"}.fa-yen-sign:before{content:"\f157"}.fa-yoast:before{content:"\f2b1"}.fa-youtube:before{content:"\f167"}.fa-youtube-square:before{content:"\f431"}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}@font-face{font-family:Font Awesome\ 5 Brands;font-style:normal;font-weight:400;src:url(../webfonts/fa-brands-400.eot);src:url(../webfonts/fa-brands-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.woff) format("woff"),url(../webfonts/fa-brands-400.ttf) format("truetype"),url(../webfonts/fa-brands-400.svg#fontawesome) format("svg")}.fab{font-family:Font Awesome\ 5 Brands}@font-face{font-family:Font Awesome\ 5 Free;font-style:normal;font-weight:400;src:url(../webfonts/fa-regular-400.eot);src:url(../webfonts/fa-regular-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.woff) format("woff"),url(../webfonts/fa-regular-400.ttf) format("truetype"),url(../webfonts/fa-regular-400.svg#fontawesome) format("svg")}.far{font-weight:400}@font-face{font-family:Font Awesome\ 5 Free;font-style:normal;font-weight:900;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.far,.fas{font-family:Font Awesome\ 5 Free}.fa,.fas{font-weight:900} \ No newline at end of file +/* FONT PATH + * -------------------------- */ +@font-face { + font-family: 'FontAwesome'; + src: url('../fonts/fontawesome-webfont.eot?v=4.7.0'); + src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'), url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg'); + font-weight: normal; + font-style: normal; +} +.fa { + display: inline-block; + font: normal normal normal 14px/1 FontAwesome; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +/* makes the font 33% larger relative to the icon container */ +.fa-lg { + font-size: 1.33333333em; + line-height: 0.75em; + vertical-align: -15%; +} +.fa-2x { + font-size: 2em; +} +.fa-3x { + font-size: 3em; +} +.fa-4x { + font-size: 4em; +} +.fa-5x { + font-size: 5em; +} +.fa-fw { + width: 1.28571429em; + text-align: center; +} +.fa-ul { + padding-left: 0; + margin-left: 2.14285714em; + list-style-type: none; +} +.fa-ul > li { + position: relative; +} +.fa-li { + position: absolute; + left: -2.14285714em; + width: 2.14285714em; + top: 0.14285714em; + text-align: center; +} +.fa-li.fa-lg { + left: -1.85714286em; +} +.fa-border { + padding: .2em .25em .15em; + border: solid 0.08em #eeeeee; + border-radius: .1em; +} +.fa-pull-left { + float: left; +} +.fa-pull-right { + float: right; +} +.fa.fa-pull-left { + margin-right: .3em; +} +.fa.fa-pull-right { + margin-left: .3em; +} +/* Deprecated as of 4.4.0 */ +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.fa.pull-left { + margin-right: .3em; +} +.fa.pull-right { + margin-left: .3em; +} +.fa-spin { + -webkit-animation: fa-spin 2s infinite linear; + animation: fa-spin 2s infinite linear; +} +.fa-pulse { + -webkit-animation: fa-spin 1s infinite steps(8); + animation: fa-spin 1s infinite steps(8); +} +@-webkit-keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} +@keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} +.fa-rotate-90 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)"; + -webkit-transform: rotate(90deg); + -ms-transform: rotate(90deg); + transform: rotate(90deg); +} +.fa-rotate-180 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)"; + -webkit-transform: rotate(180deg); + -ms-transform: rotate(180deg); + transform: rotate(180deg); +} +.fa-rotate-270 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)"; + -webkit-transform: rotate(270deg); + -ms-transform: rotate(270deg); + transform: rotate(270deg); +} +.fa-flip-horizontal { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)"; + -webkit-transform: scale(-1, 1); + -ms-transform: scale(-1, 1); + transform: scale(-1, 1); +} +.fa-flip-vertical { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"; + -webkit-transform: scale(1, -1); + -ms-transform: scale(1, -1); + transform: scale(1, -1); +} +:root .fa-rotate-90, +:root .fa-rotate-180, +:root .fa-rotate-270, +:root .fa-flip-horizontal, +:root .fa-flip-vertical { + filter: none; +} +.fa-stack { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: middle; +} +.fa-stack-1x, +.fa-stack-2x { + position: absolute; + left: 0; + width: 100%; + text-align: center; +} +.fa-stack-1x { + line-height: inherit; +} +.fa-stack-2x { + font-size: 2em; +} +.fa-inverse { + color: #ffffff; +} +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen + readers do not read off random characters that represent icons */ +.fa-glass:before { + content: "\f000"; +} +.fa-music:before { + content: "\f001"; +} +.fa-search:before { + content: "\f002"; +} +.fa-envelope-o:before { + content: "\f003"; +} +.fa-heart:before { + content: "\f004"; +} +.fa-star:before { + content: "\f005"; +} +.fa-star-o:before { + content: "\f006"; +} +.fa-user:before { + content: "\f007"; +} +.fa-film:before { + content: "\f008"; +} +.fa-th-large:before { + content: "\f009"; +} +.fa-th:before { + content: "\f00a"; +} +.fa-th-list:before { + content: "\f00b"; +} +.fa-check:before { + content: "\f00c"; +} +.fa-remove:before, +.fa-close:before, +.fa-times:before { + content: "\f00d"; +} +.fa-search-plus:before { + content: "\f00e"; +} +.fa-search-minus:before { + content: "\f010"; +} +.fa-power-off:before { + content: "\f011"; +} +.fa-signal:before { + content: "\f012"; +} +.fa-gear:before, +.fa-cog:before { + content: "\f013"; +} +.fa-trash-o:before { + content: "\f014"; +} +.fa-home:before { + content: "\f015"; +} +.fa-file-o:before { + content: "\f016"; +} +.fa-clock-o:before { + content: "\f017"; +} +.fa-road:before { + content: "\f018"; +} +.fa-download:before { + content: "\f019"; +} +.fa-arrow-circle-o-down:before { + content: "\f01a"; +} +.fa-arrow-circle-o-up:before { + content: "\f01b"; +} +.fa-inbox:before { + content: "\f01c"; +} +.fa-play-circle-o:before { + content: "\f01d"; +} +.fa-rotate-right:before, +.fa-repeat:before { + content: "\f01e"; +} +.fa-refresh:before { + content: "\f021"; +} +.fa-list-alt:before { + content: "\f022"; +} +.fa-lock:before { + content: "\f023"; +} +.fa-flag:before { + content: "\f024"; +} +.fa-headphones:before { + content: "\f025"; +} +.fa-volume-off:before { + content: "\f026"; +} +.fa-volume-down:before { + content: "\f027"; +} +.fa-volume-up:before { + content: "\f028"; +} +.fa-qrcode:before { + content: "\f029"; +} +.fa-barcode:before { + content: "\f02a"; +} +.fa-tag:before { + content: "\f02b"; +} +.fa-tags:before { + content: "\f02c"; +} +.fa-book:before { + content: "\f02d"; +} +.fa-bookmark:before { + content: "\f02e"; +} +.fa-print:before { + content: "\f02f"; +} +.fa-camera:before { + content: "\f030"; +} +.fa-font:before { + content: "\f031"; +} +.fa-bold:before { + content: "\f032"; +} +.fa-italic:before { + content: "\f033"; +} +.fa-text-height:before { + content: "\f034"; +} +.fa-text-width:before { + content: "\f035"; +} +.fa-align-left:before { + content: "\f036"; +} +.fa-align-center:before { + content: "\f037"; +} +.fa-align-right:before { + content: "\f038"; +} +.fa-align-justify:before { + content: "\f039"; +} +.fa-list:before { + content: "\f03a"; +} +.fa-dedent:before, +.fa-outdent:before { + content: "\f03b"; +} +.fa-indent:before { + content: "\f03c"; +} +.fa-video-camera:before { + content: "\f03d"; +} +.fa-photo:before, +.fa-image:before, +.fa-picture-o:before { + content: "\f03e"; +} +.fa-pencil:before { + content: "\f040"; +} +.fa-map-marker:before { + content: "\f041"; +} +.fa-adjust:before { + content: "\f042"; +} +.fa-tint:before { + content: "\f043"; +} +.fa-edit:before, +.fa-pencil-square-o:before { + content: "\f044"; +} +.fa-share-square-o:before { + content: "\f045"; +} +.fa-check-square-o:before { + content: "\f046"; +} +.fa-arrows:before { + content: "\f047"; +} +.fa-step-backward:before { + content: "\f048"; +} +.fa-fast-backward:before { + content: "\f049"; +} +.fa-backward:before { + content: "\f04a"; +} +.fa-play:before { + content: "\f04b"; +} +.fa-pause:before { + content: "\f04c"; +} +.fa-stop:before { + content: "\f04d"; +} +.fa-forward:before { + content: "\f04e"; +} +.fa-fast-forward:before { + content: "\f050"; +} +.fa-step-forward:before { + content: "\f051"; +} +.fa-eject:before { + content: "\f052"; +} +.fa-chevron-left:before { + content: "\f053"; +} +.fa-chevron-right:before { + content: "\f054"; +} +.fa-plus-circle:before { + content: "\f055"; +} +.fa-minus-circle:before { + content: "\f056"; +} +.fa-times-circle:before { + content: "\f057"; +} +.fa-check-circle:before { + content: "\f058"; +} +.fa-question-circle:before { + content: "\f059"; +} +.fa-info-circle:before { + content: "\f05a"; +} +.fa-crosshairs:before { + content: "\f05b"; +} +.fa-times-circle-o:before { + content: "\f05c"; +} +.fa-check-circle-o:before { + content: "\f05d"; +} +.fa-ban:before { + content: "\f05e"; +} +.fa-arrow-left:before { + content: "\f060"; +} +.fa-arrow-right:before { + content: "\f061"; +} +.fa-arrow-up:before { + content: "\f062"; +} +.fa-arrow-down:before { + content: "\f063"; +} +.fa-mail-forward:before, +.fa-share:before { + content: "\f064"; +} +.fa-expand:before { + content: "\f065"; +} +.fa-compress:before { + content: "\f066"; +} +.fa-plus:before { + content: "\f067"; +} +.fa-minus:before { + content: "\f068"; +} +.fa-asterisk:before { + content: "\f069"; +} +.fa-exclamation-circle:before { + content: "\f06a"; +} +.fa-gift:before { + content: "\f06b"; +} +.fa-leaf:before { + content: "\f06c"; +} +.fa-fire:before { + content: "\f06d"; +} +.fa-eye:before { + content: "\f06e"; +} +.fa-eye-slash:before { + content: "\f070"; +} +.fa-warning:before, +.fa-exclamation-triangle:before { + content: "\f071"; +} +.fa-plane:before { + content: "\f072"; +} +.fa-calendar:before { + content: "\f073"; +} +.fa-random:before { + content: "\f074"; +} +.fa-comment:before { + content: "\f075"; +} +.fa-magnet:before { + content: "\f076"; +} +.fa-chevron-up:before { + content: "\f077"; +} +.fa-chevron-down:before { + content: "\f078"; +} +.fa-retweet:before { + content: "\f079"; +} +.fa-shopping-cart:before { + content: "\f07a"; +} +.fa-folder:before { + content: "\f07b"; +} +.fa-folder-open:before { + content: "\f07c"; +} +.fa-arrows-v:before { + content: "\f07d"; +} +.fa-arrows-h:before { + content: "\f07e"; +} +.fa-bar-chart-o:before, +.fa-bar-chart:before { + content: "\f080"; +} +.fa-twitter-square:before { + content: "\f081"; +} +.fa-facebook-square:before { + content: "\f082"; +} +.fa-camera-retro:before { + content: "\f083"; +} +.fa-key:before { + content: "\f084"; +} +.fa-gears:before, +.fa-cogs:before { + content: "\f085"; +} +.fa-comments:before { + content: "\f086"; +} +.fa-thumbs-o-up:before { + content: "\f087"; +} +.fa-thumbs-o-down:before { + content: "\f088"; +} +.fa-star-half:before { + content: "\f089"; +} +.fa-heart-o:before { + content: "\f08a"; +} +.fa-sign-out:before { + content: "\f08b"; +} +.fa-linkedin-square:before { + content: "\f08c"; +} +.fa-thumb-tack:before { + content: "\f08d"; +} +.fa-external-link:before { + content: "\f08e"; +} +.fa-sign-in:before { + content: "\f090"; +} +.fa-trophy:before { + content: "\f091"; +} +.fa-github-square:before { + content: "\f092"; +} +.fa-upload:before { + content: "\f093"; +} +.fa-lemon-o:before { + content: "\f094"; +} +.fa-phone:before { + content: "\f095"; +} +.fa-square-o:before { + content: "\f096"; +} +.fa-bookmark-o:before { + content: "\f097"; +} +.fa-phone-square:before { + content: "\f098"; +} +.fa-twitter:before { + content: "\f099"; +} +.fa-facebook-f:before, +.fa-facebook:before { + content: "\f09a"; +} +.fa-github:before { + content: "\f09b"; +} +.fa-unlock:before { + content: "\f09c"; +} +.fa-credit-card:before { + content: "\f09d"; +} +.fa-feed:before, +.fa-rss:before { + content: "\f09e"; +} +.fa-hdd-o:before { + content: "\f0a0"; +} +.fa-bullhorn:before { + content: "\f0a1"; +} +.fa-bell:before { + content: "\f0f3"; +} +.fa-certificate:before { + content: "\f0a3"; +} +.fa-hand-o-right:before { + content: "\f0a4"; +} +.fa-hand-o-left:before { + content: "\f0a5"; +} +.fa-hand-o-up:before { + content: "\f0a6"; +} +.fa-hand-o-down:before { + content: "\f0a7"; +} +.fa-arrow-circle-left:before { + content: "\f0a8"; +} +.fa-arrow-circle-right:before { + content: "\f0a9"; +} +.fa-arrow-circle-up:before { + content: "\f0aa"; +} +.fa-arrow-circle-down:before { + content: "\f0ab"; +} +.fa-globe:before { + content: "\f0ac"; +} +.fa-wrench:before { + content: "\f0ad"; +} +.fa-tasks:before { + content: "\f0ae"; +} +.fa-filter:before { + content: "\f0b0"; +} +.fa-briefcase:before { + content: "\f0b1"; +} +.fa-arrows-alt:before { + content: "\f0b2"; +} +.fa-group:before, +.fa-users:before { + content: "\f0c0"; +} +.fa-chain:before, +.fa-link:before { + content: "\f0c1"; +} +.fa-cloud:before { + content: "\f0c2"; +} +.fa-flask:before { + content: "\f0c3"; +} +.fa-cut:before, +.fa-scissors:before { + content: "\f0c4"; +} +.fa-copy:before, +.fa-files-o:before { + content: "\f0c5"; +} +.fa-paperclip:before { + content: "\f0c6"; +} +.fa-save:before, +.fa-floppy-o:before { + content: "\f0c7"; +} +.fa-square:before { + content: "\f0c8"; +} +.fa-navicon:before, +.fa-reorder:before, +.fa-bars:before { + content: "\f0c9"; +} +.fa-list-ul:before { + content: "\f0ca"; +} +.fa-list-ol:before { + content: "\f0cb"; +} +.fa-strikethrough:before { + content: "\f0cc"; +} +.fa-underline:before { + content: "\f0cd"; +} +.fa-table:before { + content: "\f0ce"; +} +.fa-magic:before { + content: "\f0d0"; +} +.fa-truck:before { + content: "\f0d1"; +} +.fa-pinterest:before { + content: "\f0d2"; +} +.fa-pinterest-square:before { + content: "\f0d3"; +} +.fa-google-plus-square:before { + content: "\f0d4"; +} +.fa-google-plus:before { + content: "\f0d5"; +} +.fa-money:before { + content: "\f0d6"; +} +.fa-caret-down:before { + content: "\f0d7"; +} +.fa-caret-up:before { + content: "\f0d8"; +} +.fa-caret-left:before { + content: "\f0d9"; +} +.fa-caret-right:before { + content: "\f0da"; +} +.fa-columns:before { + content: "\f0db"; +} +.fa-unsorted:before, +.fa-sort:before { + content: "\f0dc"; +} +.fa-sort-down:before, +.fa-sort-desc:before { + content: "\f0dd"; +} +.fa-sort-up:before, +.fa-sort-asc:before { + content: "\f0de"; +} +.fa-envelope:before { + content: "\f0e0"; +} +.fa-linkedin:before { + content: "\f0e1"; +} +.fa-rotate-left:before, +.fa-undo:before { + content: "\f0e2"; +} +.fa-legal:before, +.fa-gavel:before { + content: "\f0e3"; +} +.fa-dashboard:before, +.fa-tachometer:before { + content: "\f0e4"; +} +.fa-comment-o:before { + content: "\f0e5"; +} +.fa-comments-o:before { + content: "\f0e6"; +} +.fa-flash:before, +.fa-bolt:before { + content: "\f0e7"; +} +.fa-sitemap:before { + content: "\f0e8"; +} +.fa-umbrella:before { + content: "\f0e9"; +} +.fa-paste:before, +.fa-clipboard:before { + content: "\f0ea"; +} +.fa-lightbulb-o:before { + content: "\f0eb"; +} +.fa-exchange:before { + content: "\f0ec"; +} +.fa-cloud-download:before { + content: "\f0ed"; +} +.fa-cloud-upload:before { + content: "\f0ee"; +} +.fa-user-md:before { + content: "\f0f0"; +} +.fa-stethoscope:before { + content: "\f0f1"; +} +.fa-suitcase:before { + content: "\f0f2"; +} +.fa-bell-o:before { + content: "\f0a2"; +} +.fa-coffee:before { + content: "\f0f4"; +} +.fa-cutlery:before { + content: "\f0f5"; +} +.fa-file-text-o:before { + content: "\f0f6"; +} +.fa-building-o:before { + content: "\f0f7"; +} +.fa-hospital-o:before { + content: "\f0f8"; +} +.fa-ambulance:before { + content: "\f0f9"; +} +.fa-medkit:before { + content: "\f0fa"; +} +.fa-fighter-jet:before { + content: "\f0fb"; +} +.fa-beer:before { + content: "\f0fc"; +} +.fa-h-square:before { + content: "\f0fd"; +} +.fa-plus-square:before { + content: "\f0fe"; +} +.fa-angle-double-left:before { + content: "\f100"; +} +.fa-angle-double-right:before { + content: "\f101"; +} +.fa-angle-double-up:before { + content: "\f102"; +} +.fa-angle-double-down:before { + content: "\f103"; +} +.fa-angle-left:before { + content: "\f104"; +} +.fa-angle-right:before { + content: "\f105"; +} +.fa-angle-up:before { + content: "\f106"; +} +.fa-angle-down:before { + content: "\f107"; +} +.fa-desktop:before { + content: "\f108"; +} +.fa-laptop:before { + content: "\f109"; +} +.fa-tablet:before { + content: "\f10a"; +} +.fa-mobile-phone:before, +.fa-mobile:before { + content: "\f10b"; +} +.fa-circle-o:before { + content: "\f10c"; +} +.fa-quote-left:before { + content: "\f10d"; +} +.fa-quote-right:before { + content: "\f10e"; +} +.fa-spinner:before { + content: "\f110"; +} +.fa-circle:before { + content: "\f111"; +} +.fa-mail-reply:before, +.fa-reply:before { + content: "\f112"; +} +.fa-github-alt:before { + content: "\f113"; +} +.fa-folder-o:before { + content: "\f114"; +} +.fa-folder-open-o:before { + content: "\f115"; +} +.fa-smile-o:before { + content: "\f118"; +} +.fa-frown-o:before { + content: "\f119"; +} +.fa-meh-o:before { + content: "\f11a"; +} +.fa-gamepad:before { + content: "\f11b"; +} +.fa-keyboard-o:before { + content: "\f11c"; +} +.fa-flag-o:before { + content: "\f11d"; +} +.fa-flag-checkered:before { + content: "\f11e"; +} +.fa-terminal:before { + content: "\f120"; +} +.fa-code:before { + content: "\f121"; +} +.fa-mail-reply-all:before, +.fa-reply-all:before { + content: "\f122"; +} +.fa-star-half-empty:before, +.fa-star-half-full:before, +.fa-star-half-o:before { + content: "\f123"; +} +.fa-location-arrow:before { + content: "\f124"; +} +.fa-crop:before { + content: "\f125"; +} +.fa-code-fork:before { + content: "\f126"; +} +.fa-unlink:before, +.fa-chain-broken:before { + content: "\f127"; +} +.fa-question:before { + content: "\f128"; +} +.fa-info:before { + content: "\f129"; +} +.fa-exclamation:before { + content: "\f12a"; +} +.fa-superscript:before { + content: "\f12b"; +} +.fa-subscript:before { + content: "\f12c"; +} +.fa-eraser:before { + content: "\f12d"; +} +.fa-puzzle-piece:before { + content: "\f12e"; +} +.fa-microphone:before { + content: "\f130"; +} +.fa-microphone-slash:before { + content: "\f131"; +} +.fa-shield:before { + content: "\f132"; +} +.fa-calendar-o:before { + content: "\f133"; +} +.fa-fire-extinguisher:before { + content: "\f134"; +} +.fa-rocket:before { + content: "\f135"; +} +.fa-maxcdn:before { + content: "\f136"; +} +.fa-chevron-circle-left:before { + content: "\f137"; +} +.fa-chevron-circle-right:before { + content: "\f138"; +} +.fa-chevron-circle-up:before { + content: "\f139"; +} +.fa-chevron-circle-down:before { + content: "\f13a"; +} +.fa-html5:before { + content: "\f13b"; +} +.fa-css3:before { + content: "\f13c"; +} +.fa-anchor:before { + content: "\f13d"; +} +.fa-unlock-alt:before { + content: "\f13e"; +} +.fa-bullseye:before { + content: "\f140"; +} +.fa-ellipsis-h:before { + content: "\f141"; +} +.fa-ellipsis-v:before { + content: "\f142"; +} +.fa-rss-square:before { + content: "\f143"; +} +.fa-play-circle:before { + content: "\f144"; +} +.fa-ticket:before { + content: "\f145"; +} +.fa-minus-square:before { + content: "\f146"; +} +.fa-minus-square-o:before { + content: "\f147"; +} +.fa-level-up:before { + content: "\f148"; +} +.fa-level-down:before { + content: "\f149"; +} +.fa-check-square:before { + content: "\f14a"; +} +.fa-pencil-square:before { + content: "\f14b"; +} +.fa-external-link-square:before { + content: "\f14c"; +} +.fa-share-square:before { + content: "\f14d"; +} +.fa-compass:before { + content: "\f14e"; +} +.fa-toggle-down:before, +.fa-caret-square-o-down:before { + content: "\f150"; +} +.fa-toggle-up:before, +.fa-caret-square-o-up:before { + content: "\f151"; +} +.fa-toggle-right:before, +.fa-caret-square-o-right:before { + content: "\f152"; +} +.fa-euro:before, +.fa-eur:before { + content: "\f153"; +} +.fa-gbp:before { + content: "\f154"; +} +.fa-dollar:before, +.fa-usd:before { + content: "\f155"; +} +.fa-rupee:before, +.fa-inr:before { + content: "\f156"; +} +.fa-cny:before, +.fa-rmb:before, +.fa-yen:before, +.fa-jpy:before { + content: "\f157"; +} +.fa-ruble:before, +.fa-rouble:before, +.fa-rub:before { + content: "\f158"; +} +.fa-won:before, +.fa-krw:before { + content: "\f159"; +} +.fa-bitcoin:before, +.fa-btc:before { + content: "\f15a"; +} +.fa-file:before { + content: "\f15b"; +} +.fa-file-text:before { + content: "\f15c"; +} +.fa-sort-alpha-asc:before { + content: "\f15d"; +} +.fa-sort-alpha-desc:before { + content: "\f15e"; +} +.fa-sort-amount-asc:before { + content: "\f160"; +} +.fa-sort-amount-desc:before { + content: "\f161"; +} +.fa-sort-numeric-asc:before { + content: "\f162"; +} +.fa-sort-numeric-desc:before { + content: "\f163"; +} +.fa-thumbs-up:before { + content: "\f164"; +} +.fa-thumbs-down:before { + content: "\f165"; +} +.fa-youtube-square:before { + content: "\f166"; +} +.fa-youtube:before { + content: "\f167"; +} +.fa-xing:before { + content: "\f168"; +} +.fa-xing-square:before { + content: "\f169"; +} +.fa-youtube-play:before { + content: "\f16a"; +} +.fa-dropbox:before { + content: "\f16b"; +} +.fa-stack-overflow:before { + content: "\f16c"; +} +.fa-instagram:before { + content: "\f16d"; +} +.fa-flickr:before { + content: "\f16e"; +} +.fa-adn:before { + content: "\f170"; +} +.fa-bitbucket:before { + content: "\f171"; +} +.fa-bitbucket-square:before { + content: "\f172"; +} +.fa-tumblr:before { + content: "\f173"; +} +.fa-tumblr-square:before { + content: "\f174"; +} +.fa-long-arrow-down:before { + content: "\f175"; +} +.fa-long-arrow-up:before { + content: "\f176"; +} +.fa-long-arrow-left:before { + content: "\f177"; +} +.fa-long-arrow-right:before { + content: "\f178"; +} +.fa-apple:before { + content: "\f179"; +} +.fa-windows:before { + content: "\f17a"; +} +.fa-android:before { + content: "\f17b"; +} +.fa-linux:before { + content: "\f17c"; +} +.fa-dribbble:before { + content: "\f17d"; +} +.fa-skype:before { + content: "\f17e"; +} +.fa-foursquare:before { + content: "\f180"; +} +.fa-trello:before { + content: "\f181"; +} +.fa-female:before { + content: "\f182"; +} +.fa-male:before { + content: "\f183"; +} +.fa-gittip:before, +.fa-gratipay:before { + content: "\f184"; +} +.fa-sun-o:before { + content: "\f185"; +} +.fa-moon-o:before { + content: "\f186"; +} +.fa-archive:before { + content: "\f187"; +} +.fa-bug:before { + content: "\f188"; +} +.fa-vk:before { + content: "\f189"; +} +.fa-weibo:before { + content: "\f18a"; +} +.fa-renren:before { + content: "\f18b"; +} +.fa-pagelines:before { + content: "\f18c"; +} +.fa-stack-exchange:before { + content: "\f18d"; +} +.fa-arrow-circle-o-right:before { + content: "\f18e"; +} +.fa-arrow-circle-o-left:before { + content: "\f190"; +} +.fa-toggle-left:before, +.fa-caret-square-o-left:before { + content: "\f191"; +} +.fa-dot-circle-o:before { + content: "\f192"; +} +.fa-wheelchair:before { + content: "\f193"; +} +.fa-vimeo-square:before { + content: "\f194"; +} +.fa-turkish-lira:before, +.fa-try:before { + content: "\f195"; +} +.fa-plus-square-o:before { + content: "\f196"; +} +.fa-space-shuttle:before { + content: "\f197"; +} +.fa-slack:before { + content: "\f198"; +} +.fa-envelope-square:before { + content: "\f199"; +} +.fa-wordpress:before { + content: "\f19a"; +} +.fa-openid:before { + content: "\f19b"; +} +.fa-institution:before, +.fa-bank:before, +.fa-university:before { + content: "\f19c"; +} +.fa-mortar-board:before, +.fa-graduation-cap:before { + content: "\f19d"; +} +.fa-yahoo:before { + content: "\f19e"; +} +.fa-google:before { + content: "\f1a0"; +} +.fa-reddit:before { + content: "\f1a1"; +} +.fa-reddit-square:before { + content: "\f1a2"; +} +.fa-stumbleupon-circle:before { + content: "\f1a3"; +} +.fa-stumbleupon:before { + content: "\f1a4"; +} +.fa-delicious:before { + content: "\f1a5"; +} +.fa-digg:before { + content: "\f1a6"; +} +.fa-pied-piper-pp:before { + content: "\f1a7"; +} +.fa-pied-piper-alt:before { + content: "\f1a8"; +} +.fa-drupal:before { + content: "\f1a9"; +} +.fa-joomla:before { + content: "\f1aa"; +} +.fa-language:before { + content: "\f1ab"; +} +.fa-fax:before { + content: "\f1ac"; +} +.fa-building:before { + content: "\f1ad"; +} +.fa-child:before { + content: "\f1ae"; +} +.fa-paw:before { + content: "\f1b0"; +} +.fa-spoon:before { + content: "\f1b1"; +} +.fa-cube:before { + content: "\f1b2"; +} +.fa-cubes:before { + content: "\f1b3"; +} +.fa-behance:before { + content: "\f1b4"; +} +.fa-behance-square:before { + content: "\f1b5"; +} +.fa-steam:before { + content: "\f1b6"; +} +.fa-steam-square:before { + content: "\f1b7"; +} +.fa-recycle:before { + content: "\f1b8"; +} +.fa-automobile:before, +.fa-car:before { + content: "\f1b9"; +} +.fa-cab:before, +.fa-taxi:before { + content: "\f1ba"; +} +.fa-tree:before { + content: "\f1bb"; +} +.fa-spotify:before { + content: "\f1bc"; +} +.fa-deviantart:before { + content: "\f1bd"; +} +.fa-soundcloud:before { + content: "\f1be"; +} +.fa-database:before { + content: "\f1c0"; +} +.fa-file-pdf-o:before { + content: "\f1c1"; +} +.fa-file-word-o:before { + content: "\f1c2"; +} +.fa-file-excel-o:before { + content: "\f1c3"; +} +.fa-file-powerpoint-o:before { + content: "\f1c4"; +} +.fa-file-photo-o:before, +.fa-file-picture-o:before, +.fa-file-image-o:before { + content: "\f1c5"; +} +.fa-file-zip-o:before, +.fa-file-archive-o:before { + content: "\f1c6"; +} +.fa-file-sound-o:before, +.fa-file-audio-o:before { + content: "\f1c7"; +} +.fa-file-movie-o:before, +.fa-file-video-o:before { + content: "\f1c8"; +} +.fa-file-code-o:before { + content: "\f1c9"; +} +.fa-vine:before { + content: "\f1ca"; +} +.fa-codepen:before { + content: "\f1cb"; +} +.fa-jsfiddle:before { + content: "\f1cc"; +} +.fa-life-bouy:before, +.fa-life-buoy:before, +.fa-life-saver:before, +.fa-support:before, +.fa-life-ring:before { + content: "\f1cd"; +} +.fa-circle-o-notch:before { + content: "\f1ce"; +} +.fa-ra:before, +.fa-resistance:before, +.fa-rebel:before { + content: "\f1d0"; +} +.fa-ge:before, +.fa-empire:before { + content: "\f1d1"; +} +.fa-git-square:before { + content: "\f1d2"; +} +.fa-git:before { + content: "\f1d3"; +} +.fa-y-combinator-square:before, +.fa-yc-square:before, +.fa-hacker-news:before { + content: "\f1d4"; +} +.fa-tencent-weibo:before { + content: "\f1d5"; +} +.fa-qq:before { + content: "\f1d6"; +} +.fa-wechat:before, +.fa-weixin:before { + content: "\f1d7"; +} +.fa-send:before, +.fa-paper-plane:before { + content: "\f1d8"; +} +.fa-send-o:before, +.fa-paper-plane-o:before { + content: "\f1d9"; +} +.fa-history:before { + content: "\f1da"; +} +.fa-circle-thin:before { + content: "\f1db"; +} +.fa-header:before { + content: "\f1dc"; +} +.fa-paragraph:before { + content: "\f1dd"; +} +.fa-sliders:before { + content: "\f1de"; +} +.fa-share-alt:before { + content: "\f1e0"; +} +.fa-share-alt-square:before { + content: "\f1e1"; +} +.fa-bomb:before { + content: "\f1e2"; +} +.fa-soccer-ball-o:before, +.fa-futbol-o:before { + content: "\f1e3"; +} +.fa-tty:before { + content: "\f1e4"; +} +.fa-binoculars:before { + content: "\f1e5"; +} +.fa-plug:before { + content: "\f1e6"; +} +.fa-slideshare:before { + content: "\f1e7"; +} +.fa-twitch:before { + content: "\f1e8"; +} +.fa-yelp:before { + content: "\f1e9"; +} +.fa-newspaper-o:before { + content: "\f1ea"; +} +.fa-wifi:before { + content: "\f1eb"; +} +.fa-calculator:before { + content: "\f1ec"; +} +.fa-paypal:before { + content: "\f1ed"; +} +.fa-google-wallet:before { + content: "\f1ee"; +} +.fa-cc-visa:before { + content: "\f1f0"; +} +.fa-cc-mastercard:before { + content: "\f1f1"; +} +.fa-cc-discover:before { + content: "\f1f2"; +} +.fa-cc-amex:before { + content: "\f1f3"; +} +.fa-cc-paypal:before { + content: "\f1f4"; +} +.fa-cc-stripe:before { + content: "\f1f5"; +} +.fa-bell-slash:before { + content: "\f1f6"; +} +.fa-bell-slash-o:before { + content: "\f1f7"; +} +.fa-trash:before { + content: "\f1f8"; +} +.fa-copyright:before { + content: "\f1f9"; +} +.fa-at:before { + content: "\f1fa"; +} +.fa-eyedropper:before { + content: "\f1fb"; +} +.fa-paint-brush:before { + content: "\f1fc"; +} +.fa-birthday-cake:before { + content: "\f1fd"; +} +.fa-area-chart:before { + content: "\f1fe"; +} +.fa-pie-chart:before { + content: "\f200"; +} +.fa-line-chart:before { + content: "\f201"; +} +.fa-lastfm:before { + content: "\f202"; +} +.fa-lastfm-square:before { + content: "\f203"; +} +.fa-toggle-off:before { + content: "\f204"; +} +.fa-toggle-on:before { + content: "\f205"; +} +.fa-bicycle:before { + content: "\f206"; +} +.fa-bus:before { + content: "\f207"; +} +.fa-ioxhost:before { + content: "\f208"; +} +.fa-angellist:before { + content: "\f209"; +} +.fa-cc:before { + content: "\f20a"; +} +.fa-shekel:before, +.fa-sheqel:before, +.fa-ils:before { + content: "\f20b"; +} +.fa-meanpath:before { + content: "\f20c"; +} +.fa-buysellads:before { + content: "\f20d"; +} +.fa-connectdevelop:before { + content: "\f20e"; +} +.fa-dashcube:before { + content: "\f210"; +} +.fa-forumbee:before { + content: "\f211"; +} +.fa-leanpub:before { + content: "\f212"; +} +.fa-sellsy:before { + content: "\f213"; +} +.fa-shirtsinbulk:before { + content: "\f214"; +} +.fa-simplybuilt:before { + content: "\f215"; +} +.fa-skyatlas:before { + content: "\f216"; +} +.fa-cart-plus:before { + content: "\f217"; +} +.fa-cart-arrow-down:before { + content: "\f218"; +} +.fa-diamond:before { + content: "\f219"; +} +.fa-ship:before { + content: "\f21a"; +} +.fa-user-secret:before { + content: "\f21b"; +} +.fa-motorcycle:before { + content: "\f21c"; +} +.fa-street-view:before { + content: "\f21d"; +} +.fa-heartbeat:before { + content: "\f21e"; +} +.fa-venus:before { + content: "\f221"; +} +.fa-mars:before { + content: "\f222"; +} +.fa-mercury:before { + content: "\f223"; +} +.fa-intersex:before, +.fa-transgender:before { + content: "\f224"; +} +.fa-transgender-alt:before { + content: "\f225"; +} +.fa-venus-double:before { + content: "\f226"; +} +.fa-mars-double:before { + content: "\f227"; +} +.fa-venus-mars:before { + content: "\f228"; +} +.fa-mars-stroke:before { + content: "\f229"; +} +.fa-mars-stroke-v:before { + content: "\f22a"; +} +.fa-mars-stroke-h:before { + content: "\f22b"; +} +.fa-neuter:before { + content: "\f22c"; +} +.fa-genderless:before { + content: "\f22d"; +} +.fa-facebook-official:before { + content: "\f230"; +} +.fa-pinterest-p:before { + content: "\f231"; +} +.fa-whatsapp:before { + content: "\f232"; +} +.fa-server:before { + content: "\f233"; +} +.fa-user-plus:before { + content: "\f234"; +} +.fa-user-times:before { + content: "\f235"; +} +.fa-hotel:before, +.fa-bed:before { + content: "\f236"; +} +.fa-viacoin:before { + content: "\f237"; +} +.fa-train:before { + content: "\f238"; +} +.fa-subway:before { + content: "\f239"; +} +.fa-medium:before { + content: "\f23a"; +} +.fa-yc:before, +.fa-y-combinator:before { + content: "\f23b"; +} +.fa-optin-monster:before { + content: "\f23c"; +} +.fa-opencart:before { + content: "\f23d"; +} +.fa-expeditedssl:before { + content: "\f23e"; +} +.fa-battery-4:before, +.fa-battery:before, +.fa-battery-full:before { + content: "\f240"; +} +.fa-battery-3:before, +.fa-battery-three-quarters:before { + content: "\f241"; +} +.fa-battery-2:before, +.fa-battery-half:before { + content: "\f242"; +} +.fa-battery-1:before, +.fa-battery-quarter:before { + content: "\f243"; +} +.fa-battery-0:before, +.fa-battery-empty:before { + content: "\f244"; +} +.fa-mouse-pointer:before { + content: "\f245"; +} +.fa-i-cursor:before { + content: "\f246"; +} +.fa-object-group:before { + content: "\f247"; +} +.fa-object-ungroup:before { + content: "\f248"; +} +.fa-sticky-note:before { + content: "\f249"; +} +.fa-sticky-note-o:before { + content: "\f24a"; +} +.fa-cc-jcb:before { + content: "\f24b"; +} +.fa-cc-diners-club:before { + content: "\f24c"; +} +.fa-clone:before { + content: "\f24d"; +} +.fa-balance-scale:before { + content: "\f24e"; +} +.fa-hourglass-o:before { + content: "\f250"; +} +.fa-hourglass-1:before, +.fa-hourglass-start:before { + content: "\f251"; +} +.fa-hourglass-2:before, +.fa-hourglass-half:before { + content: "\f252"; +} +.fa-hourglass-3:before, +.fa-hourglass-end:before { + content: "\f253"; +} +.fa-hourglass:before { + content: "\f254"; +} +.fa-hand-grab-o:before, +.fa-hand-rock-o:before { + content: "\f255"; +} +.fa-hand-stop-o:before, +.fa-hand-paper-o:before { + content: "\f256"; +} +.fa-hand-scissors-o:before { + content: "\f257"; +} +.fa-hand-lizard-o:before { + content: "\f258"; +} +.fa-hand-spock-o:before { + content: "\f259"; +} +.fa-hand-pointer-o:before { + content: "\f25a"; +} +.fa-hand-peace-o:before { + content: "\f25b"; +} +.fa-trademark:before { + content: "\f25c"; +} +.fa-registered:before { + content: "\f25d"; +} +.fa-creative-commons:before { + content: "\f25e"; +} +.fa-gg:before { + content: "\f260"; +} +.fa-gg-circle:before { + content: "\f261"; +} +.fa-tripadvisor:before { + content: "\f262"; +} +.fa-odnoklassniki:before { + content: "\f263"; +} +.fa-odnoklassniki-square:before { + content: "\f264"; +} +.fa-get-pocket:before { + content: "\f265"; +} +.fa-wikipedia-w:before { + content: "\f266"; +} +.fa-safari:before { + content: "\f267"; +} +.fa-chrome:before { + content: "\f268"; +} +.fa-firefox:before { + content: "\f269"; +} +.fa-opera:before { + content: "\f26a"; +} +.fa-internet-explorer:before { + content: "\f26b"; +} +.fa-tv:before, +.fa-television:before { + content: "\f26c"; +} +.fa-contao:before { + content: "\f26d"; +} +.fa-500px:before { + content: "\f26e"; +} +.fa-amazon:before { + content: "\f270"; +} +.fa-calendar-plus-o:before { + content: "\f271"; +} +.fa-calendar-minus-o:before { + content: "\f272"; +} +.fa-calendar-times-o:before { + content: "\f273"; +} +.fa-calendar-check-o:before { + content: "\f274"; +} +.fa-industry:before { + content: "\f275"; +} +.fa-map-pin:before { + content: "\f276"; +} +.fa-map-signs:before { + content: "\f277"; +} +.fa-map-o:before { + content: "\f278"; +} +.fa-map:before { + content: "\f279"; +} +.fa-commenting:before { + content: "\f27a"; +} +.fa-commenting-o:before { + content: "\f27b"; +} +.fa-houzz:before { + content: "\f27c"; +} +.fa-vimeo:before { + content: "\f27d"; +} +.fa-black-tie:before { + content: "\f27e"; +} +.fa-fonticons:before { + content: "\f280"; +} +.fa-reddit-alien:before { + content: "\f281"; +} +.fa-edge:before { + content: "\f282"; +} +.fa-credit-card-alt:before { + content: "\f283"; +} +.fa-codiepie:before { + content: "\f284"; +} +.fa-modx:before { + content: "\f285"; +} +.fa-fort-awesome:before { + content: "\f286"; +} +.fa-usb:before { + content: "\f287"; +} +.fa-product-hunt:before { + content: "\f288"; +} +.fa-mixcloud:before { + content: "\f289"; +} +.fa-scribd:before { + content: "\f28a"; +} +.fa-pause-circle:before { + content: "\f28b"; +} +.fa-pause-circle-o:before { + content: "\f28c"; +} +.fa-stop-circle:before { + content: "\f28d"; +} +.fa-stop-circle-o:before { + content: "\f28e"; +} +.fa-shopping-bag:before { + content: "\f290"; +} +.fa-shopping-basket:before { + content: "\f291"; +} +.fa-hashtag:before { + content: "\f292"; +} +.fa-bluetooth:before { + content: "\f293"; +} +.fa-bluetooth-b:before { + content: "\f294"; +} +.fa-percent:before { + content: "\f295"; +} +.fa-gitlab:before { + content: "\f296"; +} +.fa-wpbeginner:before { + content: "\f297"; +} +.fa-wpforms:before { + content: "\f298"; +} +.fa-envira:before { + content: "\f299"; +} +.fa-universal-access:before { + content: "\f29a"; +} +.fa-wheelchair-alt:before { + content: "\f29b"; +} +.fa-question-circle-o:before { + content: "\f29c"; +} +.fa-blind:before { + content: "\f29d"; +} +.fa-audio-description:before { + content: "\f29e"; +} +.fa-volume-control-phone:before { + content: "\f2a0"; +} +.fa-braille:before { + content: "\f2a1"; +} +.fa-assistive-listening-systems:before { + content: "\f2a2"; +} +.fa-asl-interpreting:before, +.fa-american-sign-language-interpreting:before { + content: "\f2a3"; +} +.fa-deafness:before, +.fa-hard-of-hearing:before, +.fa-deaf:before { + content: "\f2a4"; +} +.fa-glide:before { + content: "\f2a5"; +} +.fa-glide-g:before { + content: "\f2a6"; +} +.fa-signing:before, +.fa-sign-language:before { + content: "\f2a7"; +} +.fa-low-vision:before { + content: "\f2a8"; +} +.fa-viadeo:before { + content: "\f2a9"; +} +.fa-viadeo-square:before { + content: "\f2aa"; +} +.fa-snapchat:before { + content: "\f2ab"; +} +.fa-snapchat-ghost:before { + content: "\f2ac"; +} +.fa-snapchat-square:before { + content: "\f2ad"; +} +.fa-pied-piper:before { + content: "\f2ae"; +} +.fa-first-order:before { + content: "\f2b0"; +} +.fa-yoast:before { + content: "\f2b1"; +} +.fa-themeisle:before { + content: "\f2b2"; +} +.fa-google-plus-circle:before, +.fa-google-plus-official:before { + content: "\f2b3"; +} +.fa-fa:before, +.fa-font-awesome:before { + content: "\f2b4"; +} +.fa-handshake-o:before { + content: "\f2b5"; +} +.fa-envelope-open:before { + content: "\f2b6"; +} +.fa-envelope-open-o:before { + content: "\f2b7"; +} +.fa-linode:before { + content: "\f2b8"; +} +.fa-address-book:before { + content: "\f2b9"; +} +.fa-address-book-o:before { + content: "\f2ba"; +} +.fa-vcard:before, +.fa-address-card:before { + content: "\f2bb"; +} +.fa-vcard-o:before, +.fa-address-card-o:before { + content: "\f2bc"; +} +.fa-user-circle:before { + content: "\f2bd"; +} +.fa-user-circle-o:before { + content: "\f2be"; +} +.fa-user-o:before { + content: "\f2c0"; +} +.fa-id-badge:before { + content: "\f2c1"; +} +.fa-drivers-license:before, +.fa-id-card:before { + content: "\f2c2"; +} +.fa-drivers-license-o:before, +.fa-id-card-o:before { + content: "\f2c3"; +} +.fa-quora:before { + content: "\f2c4"; +} +.fa-free-code-camp:before { + content: "\f2c5"; +} +.fa-telegram:before { + content: "\f2c6"; +} +.fa-thermometer-4:before, +.fa-thermometer:before, +.fa-thermometer-full:before { + content: "\f2c7"; +} +.fa-thermometer-3:before, +.fa-thermometer-three-quarters:before { + content: "\f2c8"; +} +.fa-thermometer-2:before, +.fa-thermometer-half:before { + content: "\f2c9"; +} +.fa-thermometer-1:before, +.fa-thermometer-quarter:before { + content: "\f2ca"; +} +.fa-thermometer-0:before, +.fa-thermometer-empty:before { + content: "\f2cb"; +} +.fa-shower:before { + content: "\f2cc"; +} +.fa-bathtub:before, +.fa-s15:before, +.fa-bath:before { + content: "\f2cd"; +} +.fa-podcast:before { + content: "\f2ce"; +} +.fa-window-maximize:before { + content: "\f2d0"; +} +.fa-window-minimize:before { + content: "\f2d1"; +} +.fa-window-restore:before { + content: "\f2d2"; +} +.fa-times-rectangle:before, +.fa-window-close:before { + content: "\f2d3"; +} +.fa-times-rectangle-o:before, +.fa-window-close-o:before { + content: "\f2d4"; +} +.fa-bandcamp:before { + content: "\f2d5"; +} +.fa-grav:before { + content: "\f2d6"; +} +.fa-etsy:before { + content: "\f2d7"; +} +.fa-imdb:before { + content: "\f2d8"; +} +.fa-ravelry:before { + content: "\f2d9"; +} +.fa-eercast:before { + content: "\f2da"; +} +.fa-microchip:before { + content: "\f2db"; +} +.fa-snowflake-o:before { + content: "\f2dc"; +} +.fa-superpowers:before { + content: "\f2dd"; +} +.fa-wpexplorer:before { + content: "\f2de"; +} +.fa-meetup:before { + content: "\f2e0"; +} +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; +} +.sr-only-focusable:active, +.sr-only-focusable:focus { + position: static; + width: auto; + height: auto; + margin: 0; + overflow: visible; + clip: auto; +} diff --git a/public/react/src/App.js b/public/react/src/App.js index 9c89cb1b..4e643cd8 100644 --- a/public/react/src/App.js +++ b/public/react/src/App.js @@ -73,6 +73,10 @@ const ForumsIndexComponent = Loadable({ loading: Loading, }) +const ProjectPackages=Loadable({ + loader: () => import('./modules/projectPackages/ProjectPackageIndex'), + loading: Loading, +}) const ECIndexComponent = Loadable({ loader: () => import('./modules/ec'), @@ -220,6 +224,8 @@ class App extends Component { */} + {/*众包*/} + diff --git a/public/react/src/index.js b/public/react/src/index.js index f9ff41e5..38ac53e1 100644 --- a/public/react/src/index.js +++ b/public/react/src/index.js @@ -39,11 +39,9 @@ window.__useKindEditor = false; // TODO 读取到package.json中的配置? var proxy = "http://localhost:3000" // proxy = "http://testbdweb.trustie.net" -proxy = "http://testbdweb.educoder.net" +// proxy = "http://testbdweb.educoder.net" // proxy = 'http://192.168.0.195:3000' -proxy ='https://testbdweb.educoder.net' -proxy ='http://testbdweb.educoder.net' - // proxy='https://www.educoder.net' +// proxy='https://www.educoder.net' const requestMap={}; // 在这里使用requestMap控制,避免用户通过双击等操作发出重复的请求; // 如果需要支持重复的请求,考虑config里面自定义一个allowRepeat参考来控制 diff --git a/public/react/src/modules/projectPackages/PackageIndex/PackageBanner.js b/public/react/src/modules/projectPackages/PackageIndex/PackageBanner.js new file mode 100644 index 00000000..18c5ec20 --- /dev/null +++ b/public/react/src/modules/projectPackages/PackageIndex/PackageBanner.js @@ -0,0 +1,25 @@ +import React, {Component} from 'react'; +import {Link} from "react-router-dom"; + +class PackageBanner extends Component { + constructor(props) { + super(props) + this.state = { + + } + } + componentDidMount() { + + + } + + + render() { + return ( +
    + ) + } +} + +export default PackageBanner; + diff --git a/public/react/src/modules/projectPackages/PackageIndex/PackageConcent.js b/public/react/src/modules/projectPackages/PackageIndex/PackageConcent.js new file mode 100644 index 00000000..2ba39f9c --- /dev/null +++ b/public/react/src/modules/projectPackages/PackageIndex/PackageConcent.js @@ -0,0 +1,154 @@ +import React, {Component} from 'react'; +import {Link} from "react-router-dom"; +import axios from 'axios'; +import { Input ,Icon,Button,Pagination} from 'antd'; +import '../packageconcnet.css'; + +const { Search } = Input; + + + +class PackageConcent extends Component { + constructor(props) { + super(props) + this.state = { + + } + } + componentDidMount() { + + + } + + + render() { + return ( +
    + +
    +
    +
    +
    +
    + + + {/*concent*/} +
    +
    +

    +

    + 搜索} + onSearch={value => console.log(value)} /> + +

    +

    +
    +
    + + +
    +

    +

    + 类型: +

    +
  • 全部
  • +
  • 前端开发
  • +
  • 后端开发
  • +
  • 移动开发
  • +
  • 数据库
  • +
  • 云计算和大数据
  • +
  • 运维与测试
  • +
  • 人工智能
  • +
  • 其他
  • +
    +

    + +

    + 排序: +

    +
  • 最新
  • +
  • 价格
  • +
    +

    +

    +
    + + +
    + +
    + +
    + +
    + +
    + +
    + +
    + xxxxxx +
    + +
    + +
    + ~ +
    + +
    + +
    +
    人工智能
    +
    + +
    +
    + + 人浏览 +
    +
    + + + 内竞标截止 + +
    +
    + + + 人竞标 + +
    +
    +
    + 发布于: +
    +
    + +
    + +
    +
    + +
    + +
    + + +
    +
    +
    +
    +
    +
    + ) + } +} + +export default PackageConcent; + diff --git a/public/react/src/modules/projectPackages/PackageIndex/PackageIndex.js b/public/react/src/modules/projectPackages/PackageIndex/PackageIndex.js new file mode 100644 index 00000000..08487613 --- /dev/null +++ b/public/react/src/modules/projectPackages/PackageIndex/PackageIndex.js @@ -0,0 +1,30 @@ +import React, { Component } from 'react'; +import {BrowserRouter as Router,Route,Switch} from 'react-router-dom'; + +//业务组件 +import PackageBanner from "./PackageBanner"; +import PackageConcent from "./PackageConcent"; + +class PackageIndex extends Component{ + constructor(props) { + super(props) + } + + componentDidMount(){ + + } + + render() { + return ( +
    +
    + {/*头部banner*/} + + {/*内容banner*/} + +
    +
    + ) + } +} +export default PackageIndex; \ No newline at end of file diff --git a/public/react/src/modules/projectPackages/PackageIndexNewandEdit/PackageIndexNEIBanner.js b/public/react/src/modules/projectPackages/PackageIndexNewandEdit/PackageIndexNEIBanner.js new file mode 100644 index 00000000..90892f20 --- /dev/null +++ b/public/react/src/modules/projectPackages/PackageIndexNewandEdit/PackageIndexNEIBanner.js @@ -0,0 +1,42 @@ +import React, {Component} from 'react'; +import {Link} from "react-router-dom"; +import { Steps, Divider } from 'antd'; +import 'antd/dist/antd.css'; +const { Step } = Steps; + +class PackageIndexNEIBanner extends Component { + constructor(props) { + super(props) + this.state = { + current:0 + } + } + componentDidMount() { + + + } + + onChange=(current)=>{ + debugger + console.log('onChange:', current); + this.setState({ current }); + }; + + render() { + const { current } = this.state; + return ( +
    +

    + + this.onChange(0)}/> + this.onChange(1)}/> + this.onChange(2)}/> + +

    +
    + ) + } +} + +export default PackageIndexNEIBanner; + diff --git a/public/react/src/modules/projectPackages/PackageIndexNewandEdit/PackageIndexNEIBannerConcent.js b/public/react/src/modules/projectPackages/PackageIndexNewandEdit/PackageIndexNEIBannerConcent.js new file mode 100644 index 00000000..31052d08 --- /dev/null +++ b/public/react/src/modules/projectPackages/PackageIndexNewandEdit/PackageIndexNEIBannerConcent.js @@ -0,0 +1,66 @@ +import React, {Component} from 'react'; +import {Link} from "react-router-dom"; +import axios from 'axios'; +import { Input ,Icon,Button,Pagination} from 'antd'; +import '../packageconcnet.css'; +const { Search } = Input; + +class PackageIndexNEIBannerConcent extends Component { + constructor(props) { + super(props) + this.state = { + + } + } + componentDidMount() { + + + } + + + render() { + return ( +
    +

    + +

    +
    +
    + +
    + +

    +

    +
  • 前端开发
  • +
  • 后端开发
  • +
  • 移动开发
  • +
  • 数据库
  • +
  • 云计算和大数据
  • +
  • 运维与测试
  • +
  • 人工智能
  • +
  • 其他
  • +
    +

    + + +
    + +
    + + + +
    +
    + +
    + +
    + +

    +
    + ) + } +} + +export default PackageIndexNEIBannerConcent; + diff --git a/public/react/src/modules/projectPackages/PackageIndexNewandEdit/PackageIndexNewandEditIndex.js b/public/react/src/modules/projectPackages/PackageIndexNewandEdit/PackageIndexNewandEditIndex.js new file mode 100644 index 00000000..465b0b60 --- /dev/null +++ b/public/react/src/modules/projectPackages/PackageIndexNewandEdit/PackageIndexNewandEditIndex.js @@ -0,0 +1,39 @@ +import React, { Component } from 'react'; +import {BrowserRouter as Router,Route,Switch} from 'react-router-dom'; + +//业务组件 +import PackageIndexNEIBanner from "./PackageIndexNEIBanner"; +//业务组件 +import PackageIndexNEIBannerConcent from "./PackageIndexNEIBannerConcent" + +import '../packageconcnet.css'; +class PackageIndexNewandEditIndex extends Component{ + constructor(props) { + super(props) + } + + componentDidMount(){ + console.log(this.props) + } + + render() { + return ( +
    +
    +
    + +

    + 新建 +

    + + + + + +
    +
    +
    + ) + } +} +export default PackageIndexNewandEditIndex; \ No newline at end of file diff --git a/public/react/src/modules/projectPackages/ProjectPackageIndex.js b/public/react/src/modules/projectPackages/ProjectPackageIndex.js new file mode 100644 index 00000000..a22e2712 --- /dev/null +++ b/public/react/src/modules/projectPackages/ProjectPackageIndex.js @@ -0,0 +1,45 @@ +import React, { Component } from 'react'; + +import { Redirect } from 'react-router'; + +import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; + +import Loading from '../../Loading' + +import Loadable from 'react-loadable'; +import { TPMIndexHOC } from '../tpm/TPMIndexHOC' +import { SnackbarHOC } from 'educoder' + + +const PackageIndex = Loadable({ + loader: () => import('./PackageIndex/PackageIndex'), + loading: Loading, +}) + +const PackageIndexNewandEdit = Loadable({ + loader: () => import('./PackageIndexNewandEdit/PackageIndexNewandEditIndex'), + loading: Loading, +}) + +class ProjectPackageIndex extends Component { + constructor(props) { + super(props) + } + + render() { + return ( +
    + + + {/*众包首页*/} + + + + + +
    + ); + } +} + +export default SnackbarHOC() (TPMIndexHOC (ProjectPackageIndex)) ; \ No newline at end of file diff --git a/public/react/src/modules/projectPackages/packageconcnet.css b/public/react/src/modules/projectPackages/packageconcnet.css new file mode 100644 index 00000000..2dee7258 --- /dev/null +++ b/public/react/src/modules/projectPackages/packageconcnet.css @@ -0,0 +1,71 @@ +.width1240{ + width:1240px; +} +.packinput .ant-input{ + height: 50px; + width:749px; + border-color: #E1EDF8 !important; +} + +.packinput .ant-input-group-addon .ant-btn{ + width:140px !important; + font-size: 18px; + height: 50px; + background:rgba(76,172,255,1); + margin-right:18px; +} + +.setissues{ + width:280px; + height:50px; + background:rgba(76,172,255,1); + border-radius:4px; + margin-left: 15px; +} + +.pagetype li{ + color:#8F8F8F !important; +} + +.maxwidth580{ + max-width: 580px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.mbf10{ + margin-bottom:-10px; +} + +.PackageIndexNEIBanner{ + width:1200px; + height:110px; + background:rgba(255,255,255,1); + box-shadow:0px 2px 6px 0px rgba(125,125,125,0.26); + border-radius:8px; +} + +.padding110{ + padding: 39px 110px 0px; + box-sizing: border-box; +} + +.borderccc{ + border: 1px solid #ccc; +} + +.input-100-40s{ + width: 100%; + height: 40px; + padding: 5px; + box-sizing: border-box; +} + +.fafafas{ + background-color: #fafafa!important; +} + +.fafafas:focus{ + background-color: #fff!important; +} \ No newline at end of file diff --git a/public/react/src/modules/tpm/NewHeader.js b/public/react/src/modules/tpm/NewHeader.js index aba48650..a2c6609e 100644 --- a/public/react/src/modules/tpm/NewHeader.js +++ b/public/react/src/modules/tpm/NewHeader.js @@ -133,6 +133,7 @@ class NewHeader extends Component { }, ImageUrl:"", ecUrl:null, + project_packages_url:null, ImageUrlType:false } } @@ -198,7 +199,8 @@ class NewHeader extends Component { } ).then((response) => { this.setState({ - ecUrl:response.data.ec_url + ecUrl:response.data.ec_url, + project_packages_url:response.data.project_packages_url }) }).catch((error) => { console.log(error) @@ -232,7 +234,7 @@ class NewHeader extends Component { } render() { - let {careerslist,isLogin,current_user,ImageUrl,ecUrl,ImageUrlType} = this.state; + let {careerslist,isLogin,current_user,ImageUrl,ecUrl,ImageUrlType,project_packages_url} = this.state; // const isLogin = isLogintype; // 这里不会出现未登录的情况,服务端在服务端路由时发现如果是未登录,则跳转到登录页了。 const { user, match } = this.props; /* @@ -243,6 +245,7 @@ class NewHeader extends Component { let activeShixuns = false; let activeCareers = false; let activeCourses = false; + let competitions = false; if (match.path === '/forums') { activeForums = true; } else if (match.path.startsWith('/shixuns')) { @@ -253,7 +256,9 @@ class NewHeader extends Component { activeCourses=true; }else if(match.path.startsWith('/ec_major_schools')){ activeCourses=true; - }else{ + }else if(match.path.startsWith('/competitions')){ + competitions=true; + }else{ activeIndex = true; } @@ -295,7 +300,13 @@ class NewHeader extends Component { {/*
  • 教学案例
  • */} -
  • 在线竞赛
  • + +
  • 在线竞赛
  • +
  • + + {project_packages_url===null||project_packages_url===undefined||project_packages_url===""?'':'众包'} + +
  • 交流问答
  • {ecUrl===null||ecUrl===undefined||ecUrl===""?'':'工程认证'}
  • diff --git a/public/stylesheets/educoder/edu-main.css b/public/stylesheets/educoder/edu-main.css index 3debdf6f..e5eea333 100644 --- a/public/stylesheets/educoder/edu-main.css +++ b/public/stylesheets/educoder/edu-main.css @@ -980,11 +980,11 @@ html>body #ajax-indicator { position: fixed; } margin-bottom: 20px; padding: 20px; background: white; - box-shadow:1px 3px 3px 1px rgba(156,156,156,0.16); + /*box-shadow:1px 3px 3px 1px rgba(156,156,156,0.16);*/ } .project-packages-list .project-package-item:hover{ - box-shadow:2px 6px 6px 3px rgba(156,156,156,0.16); + box-shadow: 1px 6px 16px rgba(156,156,156,0.16); opacity: 1; border-radius: 2px; } From ec8cf98f17da81dd87dd839bce233b2c79b0ef85 Mon Sep 17 00:00:00 2001 From: p31729568 Date: Thu, 11 Jul 2019 09:14:16 +0800 Subject: [PATCH 12/42] project package create/update api response add id column --- app/api/mobile/apis/project_packages.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/api/mobile/apis/project_packages.rb b/app/api/mobile/apis/project_packages.rb index 591e54b1..e619ce74 100644 --- a/app/api/mobile/apis/project_packages.rb +++ b/app/api/mobile/apis/project_packages.rb @@ -112,7 +112,7 @@ module Mobile package = current_user.project_packages.new ::ProjectPackages::SaveService.new(package, symbolize_params).call package.increment_visit_count! - render_ok + render_ok(id: package.id) rescue ::ProjectPackages::SaveService::Error => ex render_error(ex.message) end @@ -142,7 +142,7 @@ module Mobile ::ProjectPackages::SaveService.new(package, symbolize_params).call package.increment_visit_count! - render_ok + render_ok(id: package.id) rescue ::ProjectPackages::SaveService::Error => ex render_error(ex.message) end From 341d65bd6732b951f25ae781d7bdc2003719eb35 Mon Sep 17 00:00:00 2001 From: p31729568 Date: Thu, 11 Jul 2019 09:27:30 +0800 Subject: [PATCH 13/42] modify project package show api --- app/api/mobile/entities/project_package.rb | 21 +++++++++++++-------- app/models/project_package.rb | 8 ++++++-- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/app/api/mobile/entities/project_package.rb b/app/api/mobile/entities/project_package.rb index de0e7218..85f8bb14 100644 --- a/app/api/mobile/entities/project_package.rb +++ b/app/api/mobile/entities/project_package.rb @@ -20,14 +20,6 @@ module Mobile package.published_at.try(:utc).try(:iso8601) end - expose :can_bidding, if: { type: :show } do |package, opts| - package.can_bidding?(opts[:user]) - end - - expose :can_select_bidding_user, if: { type: :show } do |package, opts| - opts[:user].id == package.creator_id && !package.bidding_end? - end - expose :creator, if: { type: :show } do |package, _| { id: package.creator.id, @@ -60,6 +52,19 @@ module Mobile } end end + + expose :operation, if: { type: :show } do |package, opts| + user = opts[:user] + is_creator = user.id == package.creator_id + is_admin = user.admin? || user.business? + + { + can_bidding: package.can_bidding?(user), + can_select_bidding_user: package.bidding_end? && package.end_bidding? && (is_creator || is_admin), + can_edit: package.editable? && (is_creator || is_admin), + can_delete: package.deletable? && (is_creator || is_admin) + } + end end end end diff --git a/app/models/project_package.rb b/app/models/project_package.rb index 08d2c612..f957dc5d 100644 --- a/app/models/project_package.rb +++ b/app/models/project_package.rb @@ -68,9 +68,13 @@ class ProjectPackage < ActiveRecord::Base pending? || refused? end + def deadline? + deadline_at < Time.now + end + def bidding_end? - flag = deadline_at < Time.now - end_bidding! if flag && can_end_bidding? + flag = deadline? + end_bidding! if flag && may_end_bidding? flag end From c368f8037a905b6cecb5a0b5893ed235680476ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com> Date: Thu, 11 Jul 2019 11:09:18 +0800 Subject: [PATCH 14/42] =?UTF-8?q?=E4=BC=97=E5=8C=85=E5=8F=91=E5=B8=83?= =?UTF-8?q?=E9=9C=80=E6=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/react/src/NotFoundPage.js | 6 + .../src/modules/projectPackages/MDEditors.js | 336 ++++++++++++++++++ .../PackageIndexNEIBanner.js | 6 +- .../PackageIndexNEIBannerConcent.js | 142 +++++++- .../projectPackages/packageconcnet.css | 58 ++- public/stylesheets/educoder/attachments.js | 2 +- 6 files changed, 538 insertions(+), 12 deletions(-) create mode 100644 public/react/src/modules/projectPackages/MDEditors.js diff --git a/public/react/src/NotFoundPage.js b/public/react/src/NotFoundPage.js index 98e58d12..24a5ebd0 100644 --- a/public/react/src/NotFoundPage.js +++ b/public/react/src/NotFoundPage.js @@ -25,6 +25,12 @@ class NotFoundPage extends Component { test | 上海社区 + | + zb + | + zbne + + ); } diff --git a/public/react/src/modules/projectPackages/MDEditors.js b/public/react/src/modules/projectPackages/MDEditors.js new file mode 100644 index 00000000..c91c4d16 --- /dev/null +++ b/public/react/src/modules/projectPackages/MDEditors.js @@ -0,0 +1,336 @@ +import React, {Component} from 'react'; + +import {Input, Select, Radio, Checkbox, Popconfirm, message, Modal} from 'antd'; + +import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom"; + +import { getImageUrl, toPath, getUrl } from 'educoder'; + +require('codemirror/lib/codemirror.css'); + +let origin = getUrl(); +let path = getUrl("/editormd/lib/") + + +const $ = window.$; + +let timeout; + +let currentValue; + +const Option = Select.Option; + +const RadioGroup = Radio.Group; + + + +// 保存数据 +function md_add_data(k,mdu,d){ + window.sessionStorage.setItem(k+mdu,d); +} + +// 清空保存的数据 +function md_clear_data(k,mdu,id){ + window.sessionStorage.removeItem(k+mdu); + var id1 = "#e_tip_"+id; + var id2 = "#e_tips_"+id; + if(k == 'content'){ + $(id2).html(" "); + }else{ + $(id1).html(" "); + } +} +window.md_clear_data = md_clear_data +// editor 存在了jquery对象上,应用不需要自己写md_rec_data方法了 +function md_rec_data(k, mdu, id) { + if (window.sessionStorage.getItem(k + mdu) !== null) { + var editor = $("#e_tips_" + id).data('editor'); + editor.setValue(window.sessionStorage.getItem(k + mdu)); + // debugger; + // /shixuns/b5hjq9zm/challenges/3977/tab=3 setValue可能导致editor样式问题 + md_clear_data(k, mdu, id); + } +} +window.md_rec_data = md_rec_data; + +function md_elocalStorage(editor,mdu,id){ + if (window.sessionStorage){ + var oc = window.sessionStorage.getItem('content'+mdu); + if(oc !== null ){ + console.log("#e_tips_"+id) + $("#e_tips_"+id).data('editor', editor); + var h = '您上次有已保存的数据,是否恢复 ? / 不恢复'; + $("#e_tips_"+id).html(h); + } + setInterval(function() { + var d = new Date(); + var h = d.getHours(); + var m = d.getMinutes(); + var s = d.getSeconds(); + h = h < 10 ? '0' + h : h; + m = m < 10 ? '0' + m : m; + s = s < 10 ? '0' + s : s; + if(editor.getValue().trim() != ""){ + md_add_data("content",mdu,editor.getValue()); + var id1 = "#e_tip_"+id; + var id2 = "#e_tips_"+id; + + var textStart = " 数据已于 " + var text = textStart + h + ':' + m + ':' + s +" 保存 "; + // 占位符 + var oldHtml = $(id2).html(); + if (oldHtml && oldHtml != ' ' && oldHtml.startsWith(textStart) == false) { + $(id2).html( oldHtml.split(' (')[0] + ` (${text})`); + } else { + $(id2).html(text); + } + // $(id2).html(""); + } + },10000); + + }else{ + $("#e_tip_"+id).after('您的浏览器不支持localStorage.无法开启自动保存草稿服务,请升级浏览器!'); + } +} + + +function create_editorMD(id, width, high, placeholder, imageUrl, callback, initValue, + onchange, watch, { noStorage, showNullButton }, that) { + // 还是出现了setting只有一份,被共用的问题 + + var editorName = window.editormd(id, { + width: width, + height: high===undefined?400:high, + path: path, // "/editormd/lib/" + markdown : initValue, + + dialogLockScreen: false, + watch:watch===undefined?true:watch, + syncScrolling: "single", + tex: true, + tocm: true, + emoji: true, + taskList: true, + codeFold: true, + searchReplace: true, + htmlDecode: "style,script,iframe", + sequenceDiagram: true, + autoFocus: false, + + // mine + + toolbarIcons: function (mdEditor) { + + let react_id = `react_${id}`; + const __that = window[react_id] + + // Or return editormd.toolbarModes[name]; // full, simple, mini + // Using "||" set icons align right. + const icons = ["bold", "italic", "|", "list-ul", "list-ol", "|", "code", "code-block", "|", "testIcon", "testIcon1", '|', "image", "table", '|', "watch", "clear"]; + if (__that.props.showNullButton) { + icons.push('nullBtton') + } + return icons + + + }, + toolbarCustomIcons: { + testIcon: "
    ", + testIcon1: "
    ", + nullBtton: "
    点击插入填空项
    ", + }, + //这个配置在simple.html中并没有,但是为了能够提交表单,使用这个配置可以让构造出来的HTML代码直接在第二个隐藏的textarea域中,方便post提交表单。 + saveHTMLToTextarea: true, + // 用于增加自定义工具栏的功能,可以直接插入HTML标签,不使用默认的元素创建图标 + dialogMaskOpacity: 0.6, + placeholder: placeholder, + imageUpload: true, + imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp", "JPG", "JPEG", "GIF", "PNG", "BMP", "WEBP"], + imageUploadURL: imageUrl,//url + onchange: onchange, + onload: function() { + let _id = this.id // 如果要使用this,这里不能使用箭头函数 + let _editorName = this; + let react_id = `react_${_editorName.id}`; + const __that = window[react_id] + + // this.previewing(); + // let _id = id; + $("#" + _id + " [type=\"latex\"]").bind("click", function () { + _editorName.cm.replaceSelection("```latex"); + _editorName.cm.replaceSelection("\n"); + _editorName.cm.replaceSelection("\n"); + _editorName.cm.replaceSelection("```"); + var __Cursor = _editorName.cm.getDoc().getCursor(); + _editorName.cm.setCursor(__Cursor.line - 1, 0); + }); + + $("#" + _id + " [type=\"inline\"]").bind("click", function () { + _editorName.cm.replaceSelection("$$$$"); + var __Cursor = _editorName.cm.getDoc().getCursor(); + _editorName.cm.setCursor(__Cursor.line, __Cursor.ch - 2); + _editorName.cm.focus(); + }); + $("[type=\"inline\"]").attr("title", "行内公式"); + $("[type=\"latex\"]").attr("title", "多行公式"); + + if (__that.props.showNullButton) { + const NULL_CH = '▁' + // const NULL_CH = '〇' + // const NULL_CH = '🈳' + + $("#" + _id + " [type=\"nullBtton\"]").bind("click", function () { + _editorName.cm.replaceSelection(NULL_CH); + // var __Cursor = _editorName.cm.getDoc().getCursor(); + // _editorName.cm.setCursor(__Cursor.line - 1, 0); + }); + } + + if (noStorage == true) { + + } else { + md_elocalStorage(_editorName, `MDEditor__${_id}`, _id); + } + + callback && callback(_editorName) + } + }); + return editorName; +} + + +export default class MDEditors extends Component { + constructor(props) { + super(props) + this.state = { + initValue: '' + } + } + componentDidUpdate(prevProps, prevState) { + // 不能加,影响了试卷填空题 + // if (this.props.initValue != prevProps.initValue) { + // this.answers_editormd.setValue(this.props.initValue) + // } + } + + // react_mdEditor_ + componentDidMount = () => { + const { mdID, initValue, placeholder, showNullButton} = this.props; + + let _id = `mdEditor_${mdID}` + this.contentChanged = false; + const _placeholder = placeholder || ""; + // amp; + // 编辑时要传memoId + const imageUrl = `/api/attachments.json`; + // 创建editorMd + let react_id = `react_${_id}`; + + window[react_id] = this + const answers_editormd = create_editorMD(_id, '100%', this.props.height, _placeholder, imageUrl, (__editorName) => { + react_id = `react_${__editorName.id}`; + const that = window[react_id] + + setTimeout(() => { + console.log('timeout', __editorName.id) + __editorName.resize() + __editorName.cm && __editorName.cm.refresh() + }, that.props.refreshTimeout || 500) + if (that.props.initValue != undefined && that.props.initValue != '') { + __editorName.setValue(that.props.initValue) + } + if (that.state.initValue) { + __editorName.setValue(that.state.initValue) + } + __editorName.cm.on("change", (_cm, changeObj) => { + that.contentChanged = true; + if (that.state.showError) { + that.setState({showError: false}) + } + that.onEditorChange() + }) + that.props.onCMBlur && __editorName.cm.on('blur', () => { + that.props.onCMBlur() + }) + that.props.onCMBeforeChange && __editorName.cm.on('beforeChange', (cm,change) => { + that.props.onCMBeforeChange(cm,change) + }) + that.answers_editormd = __editorName; + window[_id] = __editorName; + }, initValue, this.onEditorChange,this.props.watch, { + noStorage: this.props.noStorage, + showNullButton: this.props.showNullButton + }, this); + + } + showError = () => { + this.setState({showError: true}) + } + onEditorChange = () => { + if (!this.answers_editormd) return; + const val = this.answers_editormd.getValue(); + try { + this.props.onChange && this.props.onChange(val) + } catch(e) { + // http://localhost:3007/courses/1309/common_homeworks/6566/setting + // 从这个页面,跳转到编辑页面,再在编辑页面点击返回的时候,这里会报错 + console.error('出错') + console.error(e) + } + } + resize = () => { + if (!this.answers_editormd) { // 还未初始化 + return; + } + this.answers_editormd.resize() + this.answers_editormd.cm && this.answers_editormd.cm.refresh() + this.answers_editormd.cm.focus() + } + + getValue = () => { + try { + return this.answers_editormd.getValue() + } catch (e) { + return '' + } + } + setValue = (val) => { + try { + this.answers_editormd.setValue(val) + } catch (e) { + // TODO 这里多实例的时候,前一个实例的state会被后面这个覆盖 参考NewWork.js http://localhost:3007/courses/1309/homework/9300/edit/1 + // 未初始化 + this.setState({ initValue: val }) + } + } + + render() { + + let { + showError + } = this.state; + let { mdID, className, noStorage } = this.props; + let _style = {} + if (showError) { + _style.border = '1px solid red' + } + return ( + +
    + {/* padding10-20 */} +
    + +
    +
    +
    +
    +
    + {noStorage == true ? ' ' :

     

    } + {/* {noStorage == true ? ' ' :

     

    } */} +
    +
    + ) + } +} + + diff --git a/public/react/src/modules/projectPackages/PackageIndexNewandEdit/PackageIndexNEIBanner.js b/public/react/src/modules/projectPackages/PackageIndexNewandEdit/PackageIndexNEIBanner.js index 90892f20..0f3d86b7 100644 --- a/public/react/src/modules/projectPackages/PackageIndexNewandEdit/PackageIndexNEIBanner.js +++ b/public/react/src/modules/projectPackages/PackageIndexNewandEdit/PackageIndexNEIBanner.js @@ -28,9 +28,9 @@ class PackageIndexNEIBanner extends Component {

    - this.onChange(0)}/> - this.onChange(1)}/> - this.onChange(2)}/> + + +

    diff --git a/public/react/src/modules/projectPackages/PackageIndexNewandEdit/PackageIndexNEIBannerConcent.js b/public/react/src/modules/projectPackages/PackageIndexNewandEdit/PackageIndexNEIBannerConcent.js index 31052d08..22032639 100644 --- a/public/react/src/modules/projectPackages/PackageIndexNewandEdit/PackageIndexNEIBannerConcent.js +++ b/public/react/src/modules/projectPackages/PackageIndexNewandEdit/PackageIndexNEIBannerConcent.js @@ -1,30 +1,44 @@ import React, {Component} from 'react'; import {Link} from "react-router-dom"; import axios from 'axios'; -import { Input ,Icon,Button,Pagination} from 'antd'; +import { Input ,Icon,Button,Pagination,DatePicker} from 'antd'; +import locale from 'antd/lib/date-picker/locale/zh_CN'; +import MDEditors from '../MDEditors'; import '../packageconcnet.css'; const { Search } = Input; class PackageIndexNEIBannerConcent extends Component { constructor(props) { super(props) + this.contentMdRef = React.createRef(); this.state = { } } + componentDidMount() { } + setclick=()=>{ + const mdContnet = this.contentMdRef.current.getValue().trim(); + console.log(mdContnet) + } + + onChangeTimePicker = (value, dateString) => { + this.setState({ + TimePickervalue: dateString + }) + } render() { return ( -
    +

    -

    -
    +
    +
    @@ -44,19 +58,133 @@ class PackageIndexNEIBannerConcent extends Component {
    - +
    - + + + + {/* 请求status 422 */} +
    + window.$('#_file').click()} + data-tip-down="请选择文件上传"> + {/**/} + 上传附件 + + (最多可添加 5 个图片/文件,每个大小不超过 10MB) +
    + +
    + + + + { + debugger; + window.addInputFiles(window.$('.file_selector')[0]) + }} + style={{'display': 'none'}} type="file"> + + +
    + + +
    - +
    +
    + +
    +

    + 竞标截止: + +

    +

    + 支付费用: + ¥ + } + /> + + ¥ + } + /> +

    +
    + +
    +

    + 姓名: + +

    +

    + 手机号: + + + + +

    +

    +
    + + 保存 +
    ) } diff --git a/public/react/src/modules/projectPackages/packageconcnet.css b/public/react/src/modules/projectPackages/packageconcnet.css index 2dee7258..f6ee42e6 100644 --- a/public/react/src/modules/projectPackages/packageconcnet.css +++ b/public/react/src/modules/projectPackages/packageconcnet.css @@ -57,15 +57,71 @@ .input-100-40s{ width: 100%; - height: 40px; padding: 5px; box-sizing: border-box; } .fafafas{ background-color: #fafafa!important; + height: 40px; } .fafafas:focus{ background-color: #fff!important; +} + +.fafas .ant-input{ + background-color: #fafafa!important; + height: 40px; +} + +.fafas .ant-input:focus{ + background-color: #fff!important; +} + + +.upload_filename{ + line-height: 32px; +} + +.attachment span{ + line-height: 23px; +} + +.attachment .remove-upload{ + line-height: 28px; +} + +.pd30a0{ + padding: 30px 30px 0 30px; +} + +.attachment .icon-fujian{ + font-size: 12px !important; + line-height: 14px; +} + +.newFormbox{ + height:20px +} + +.ml24{ + margin-left:24px; +} + +.defalutCancelbtns{ + display: block; + border: 1px solid #4CACFF !important; + background-color: #fafafa; + color: #4CACFF !important; + width:130px; + height:40px; + text-align: center; + line-height: 40px; + border-radius: 4px; +} + +.defalutSubmitbtns{ + background-color: #4CACFF; + height:40px; } \ No newline at end of file diff --git a/public/stylesheets/educoder/attachments.js b/public/stylesheets/educoder/attachments.js index 35b2b13b..03b301bc 100644 --- a/public/stylesheets/educoder/attachments.js +++ b/public/stylesheets/educoder/attachments.js @@ -114,7 +114,7 @@ function addFile(inputEl, file, eagerUpload,btnId) { fileSpan.append( $('').attr({ - 'class': 'fa fa-folder mr5 color-blue fl mt8', + 'class': 'color-green iconfont icon-fujian mr5 fl mt8', 'aria-hidden': true }), $('', { From 64f74caaf0ce917b58c2c857500443337b9d254c Mon Sep 17 00:00:00 2001 From: p31729568 Date: Thu, 11 Jul 2019 13:45:55 +0800 Subject: [PATCH 15/42] project package show api response add contact info --- app/api/mobile/entities/project_package.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/api/mobile/entities/project_package.rb b/app/api/mobile/entities/project_package.rb index 85f8bb14..7313abfc 100644 --- a/app/api/mobile/entities/project_package.rb +++ b/app/api/mobile/entities/project_package.rb @@ -12,6 +12,8 @@ module Mobile expose :bidding_users_count, if: { type: :index } expose :min_price expose :max_price + expose :contact_name, if: ->(package, opts){ opts[:user].id == package.creator_id || opts[:user].admin? || opts[:user].business? } + expose :contact_phone, if: ->(package, opts){ opts[:user].id == package.creator_id || opts[:user].admin? || opts[:user].business? } expose :deadline_at do |package, _| package.deadline_at.try(:utc).try(:iso8601) From a0214ff811013434e5b47fb3182c6d984e3c91e8 Mon Sep 17 00:00:00 2001 From: p31729568 Date: Thu, 11 Jul 2019 15:53:34 +0800 Subject: [PATCH 16/42] management project package list --- .../project_packages_controller.rb | 54 +++++++++++ app/helpers/application_helper.rb | 4 + app/models/project_package.rb | 4 + app/views/layouts/base_management.html.erb | 5 ++ .../_project_package_list.html.erb | 53 +++++++++++ .../project_packages/index.html.erb | 89 +++++++++++++++++++ .../managements/project_packages/index.js.erb | 1 + config/locales/project_packages/zh.yml | 9 +- config/routes.rb | 5 ++ public/stylesheets/educoder/edu-main.css | 9 ++ 10 files changed, 232 insertions(+), 1 deletion(-) create mode 100644 app/controllers/managements/project_packages_controller.rb create mode 100644 app/views/managements/project_packages/_project_package_list.html.erb create mode 100644 app/views/managements/project_packages/index.html.erb create mode 100644 app/views/managements/project_packages/index.js.erb diff --git a/app/controllers/managements/project_packages_controller.rb b/app/controllers/managements/project_packages_controller.rb new file mode 100644 index 00000000..4daa32bb --- /dev/null +++ b/app/controllers/managements/project_packages_controller.rb @@ -0,0 +1,54 @@ +class Managements::ProjectPackagesController < Managements::BaseController + before_filter :set_menu_type, only: [:index] + + def index + packages = ProjectPackage.where(nil) + + # 任务标题 + keyword = params[:keyword].to_s.strip + packages = packages.where('title LIKE ?', "%#{keyword}%") if keyword.present? + + # 发布者姓名 + creator_name = params[:creator_name].to_s.strip + if creator_name.present? + sql = 'LOWER(concat(users.lastname, users.firstname)) LIKE ?' + packages = packages.joins(:creator).where(sql, "%#{creator_name}%") + end + + # 状态 + status = + case params[:status] + when 'pending' then %w(pending refused) + when 'applying' then %w(applying) + when 'published' then %w(published bidding_end) + when 'finished' then %w(bidding_finished) + end + packages = packages.where(status: status) if status.present? + + # 发布时间 + begin_date = (params[:begin_date].to_time.beginning_of_day rescue nil) + end_date = (params[:end_date].to_time.end_of_day rescue nil) + packages = packages.where('published_at >= ?', begin_date) if begin_date.present? + packages = packages.where('published_at <= ?', end_date) if end_date.present? + + @count = packages.count + + # 排序 + params[:sort_by] ||= 'created_at' + params[:sort_direction] ||= 'desc' + packages = packages.order("#{params[:sort_by]} #{params[:sort_direction]}") + + @packages = paginateHelper packages.preload(:creator) + end + + def destroy + + end + + private + + def set_menu_type + @menu_type = 14 + @sub_type = 1 + end +end \ No newline at end of file diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 51825709..05e1e2ce 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -772,6 +772,10 @@ module ApplicationHelper ) ) ) + when 14 + case sub_type + when 1 then '任务列表' + end end end diff --git a/app/models/project_package.rb b/app/models/project_package.rb index f957dc5d..8f9035f6 100644 --- a/app/models/project_package.rb +++ b/app/models/project_package.rb @@ -89,4 +89,8 @@ class ProjectPackage < ActiveRecord::Base def category_text I18n.t("project_package.category.#{category}") end + + def status_text + I18n.t("project_package.status.#{status}") + end end \ No newline at end of file diff --git a/app/views/layouts/base_management.html.erb b/app/views/layouts/base_management.html.erb index c59f80a8..f0fefec5 100644 --- a/app/views/layouts/base_management.html.erb +++ b/app/views/layouts/base_management.html.erb @@ -77,6 +77,11 @@
  • <%= link_to "竞赛列表", competition_managements_path %>
  • +
  • 众包+ +
      +
    • <%= link_to "任务列表", managements_project_packages_path %>
    • +
    +
  • 单位